POJ 1698Alice's Chance(最大流)

很好的建图题,其他的没什么,就是传统的最大流。

要是能想到这么建图,这题基本就出来了。

增加一个源点s,s到每部电影连一条边,这里注意,其权值是完成该电影所需天数(这个我还有点不理解,是在POJ的Discuss里看到的),然后每部电影到该电影的拍摄日连一条边,权值为1,然后每个拍摄日到汇点t增加一条权值为1的边。至此,建图完成,求最大流就OK了。

 

代码:

#include<iostream> #include<queue> using namespace std; #define N 400 #define min(a,b) a<b?a:b int tt,sum,map[N][N],flow[N][N],minflow[N],pre[N],flag; void getmap() { int i,j,k,film_num; scanf("%d",&film_num); memset(map,0,sizeof(map)); int max=-1; sum=0; //拍完所有电影所需的天数 flag=1; //默认时间足够拍完所有电影 for(i=1;i<=film_num;i++) { int count=0; //统计第i部电影每周需要拍几天 int a[8]; for(k=1;k<=7;k++) { scanf("%d",&a[k]); if(a[k]==1) count++; } int d,w; scanf("%d%d",&d,&w); map[0][i]=d; sum+=d; if(w>max) max=w; //统计最大的week值,用来计算建图大小 if(count*w<d) flag=0; //只要有一部电影所需天数大于可用天数,flag就置为0,即不能完成,需要输出No for(j=1;j<=w;j++) { for(k=1;k<=7;k++) if(a[k]==1) map[ i ][ film_num+(j-1)*7+k ]=1; } } tt=film_num+max*7+1; //汇点的下标值 for(i=film_num+1;i<tt;i++) map[i][tt]=1; } int maxflow(int s,int t) { int cur,u,v,ans=0; memset(flow,0,sizeof(flow)); while(1) { memset(pre,-1,sizeof(pre)); memset(minflow,0,sizeof(minflow)); queue<int> q; q.push(s); minflow[s]=INT_MAX; while( !q.empty() ) { cur=q.front(); q.pop(); if(cur == t)break; for(v=s;v<=t;v++) { if(pre[v]<0 && map[cur][v]-flow[cur][v]>0) { pre[v]=cur; minflow[v]=min(minflow[cur],map[cur][v]-flow[cur][v]); q.push(v); } } } if(pre[t]==-1) break; for(v=t;v!=s;v=pre[v]) { u=pre[v]; flow[u][v]+=minflow[t]; flow[v][u]-=minflow[t]; } ans+=minflow[t]; } return ans; } int main() { int cases,result; scanf("%d",&cases); while(cases--) { getmap(); if(flag==0){printf("No/n");continue;} result=maxflow(0,tt); if(result>=sum) printf("Yes/n"); else printf("No/n"); } return 0; }  

你可能感兴趣的:(POJ 1698Alice's Chance(最大流))