2 10 1 10 6 3 2 10 4 2 2 10 1 10 5 3 2 10 4 2
Yes No
2009 Multi-University Training Contest 9 - Host by HIT
题意描述:有n个人来烤肉店吃烤肉,每个人在si 时刻来ei 时刻离开并且点了ni 份,
每份烤肉要烤到ti 个单位时间才算烤熟,烤肉店里可以同时烤m份。问是否有一种计划
使得n个人都可以拿到自己的ni 份。
参考大牛解题思路:这道题本身不是很难,网络流的模型也很常见,但是这道题中(si,ei)的时间
跨度很大(1<=si<=ei<=1000000),所以不能把时间区间直接拆分开建立模型,这样顶点
个数太多,会超时。这里,介绍一下学到的新技巧,我们可以把时间区间压缩:
time[]里保存全部的si 和 ei ,这样time[i]-time[i-1]就表示一段时间区间了,
这题和HDU 3572相似,但又不能像那题那样做,因为这题时间长度有点大
所以将时间区间当成一个点,将该区间连向超级汇点,容量为区间长度*M
将所有客人连向超级源点,容量为烤肉数量*每串烤肉所需时间
接下来的难点就是怎么将客人和时间区间连起来了 ,
如果时间区间在客人来的时间和走的时间这段区间内,
就表明这段时间可以用来帮客人烤肉,所以可以连接,容量为inf
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
#define M 3000
#define inf 0x3f3f3f3f
int head[M],dis[M],st,t,n,m,cnt;
struct node{
int v,next,w;
}mp[M*M];
void add(int u,int v,int w){
mp[cnt].v=v;
mp[cnt].w=w;
mp[cnt].next=head[u];
head[u]=cnt++;
mp[cnt].v=u;
mp[cnt].w=0;
mp[cnt].next=head[v];
head[v]=cnt++;
}
int bfs(){
memset(dis,-1,sizeof(dis));
queue <int> q;
dis[st]=0;
q.push(st);
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=mp[i].next){
int v=mp[i].v;
if( mp[i].w>0 && dis[v]==-1){
dis[v]=dis[u]+1;
if(v==t) return 1;
q.push(v);
}
}
}
return 0;
}
int dinic(int s,int low){//按照注释地方写就会wa,以前这么写就能过啊,这次快wa哭了,,= =+
if(s==t || low==0) return low;
int a,ans=low;//ans=0;
for(int i=head[s];i!=-1;i=mp[i].next){
int v=mp[i].v;
if(mp[i].w>0 && dis[v]==dis[s]+1 && (a=dinic(v,min(ans/*low*/,mp[i].w)))){
mp[i].w-=a;
mp[i^1].w+=a;
// ans+=a;
// if(ans==low) break;
ans-=a;
if(ans==0) return low;
}
}
//return ans;
return low-ans;
}
int main(){
int tot,count,sum;
int s[M],e[M],num[M],ti[M],time[M];
while(~scanf("%d%d",&n,&m)){
sum=cnt=0;tot=1; count=0;
memset(head,-1,sizeof(head));
memset(time,0,sizeof(time));
for(int i=1;i<=n;i++){
scanf("%d%d%d%d",&s[i],&num[i],&e[i],&ti[i]);
sum+=num[i]*ti[i];
time[tot++]=s[i];
time[tot++]=e[i];
}
sort(time+1,time+tot);
for(int i=1;i<tot;i++)//消除重复区域
if(time[count]!=time[i])
time[++count]=time[i];
st=n+count+1;//起点
t=st+1; //汇点
for(int i=1;i<=n;i++)//起点到每个顾客,权值为烤肉数乘以时间
add(st,i,num[i]*ti[i]);
for(int i=1;i<=count;i++){
add(n+i,t,m*(time[i]-time[i-1]));//时间区间到汇点,权值为单位时间完成烤肉m乘以区间长度
for(int j=1;j<=n;j++){
if(s[j]<=time[i-1]&&e[j]>=time[i])
add(j,n+i,inf);//如果顾客的区间段
}
}
int ans=0;
while(bfs())
ans+=dinic(st,inf);
if(sum==ans) printf("Yes\n");
else printf("No\n");
}
return 0;
} hdu 2883 kebab(时间区间压缩 && dinic)
原文:http://blog.csdn.net/ling_du/article/details/47665367