标签:
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