POJ 1698 Alice's Chance(最大流,构图题)
今天早上还算顺利,过了两题不是很水的题目,这题Alice就是一个构图题,刚开始感觉思路是有的,可能交了一边是WA就郁闷了!刚开始的思路是
“ 把源点和周一到周日相连,权值是全部电影中需要的星期最长的,如第一个例题是4,
然后 日期1到7和电影从8开始有关的相连,权值是电影需要的星期数,最后是电影到汇点的权值是需要的天数。”
话说某大神要是看到这个思想,希望提出不足之处,非常感谢!
发现不行的,之后改成了把每个电影需要的星期数都拆开,变成一条线的权值设为1,这样每个星期中的某一天只能被一部电影占据,源点直接连接到电影,权值为需要的天数,之后将日期和汇点相连,比如有一部电影需要4周,就需要有4*7=28个点和汇点相连!这样开了15000的数据,还能32MS,Dinic挺快的了!
构图题,Dinic用的还是之前的模板!没什么好讲的了!
#include <iostream> #include <stdio.h> #include <string.h> using namespace std; #define maxn 16000 const int INF=0xffffff; int f[25][9]; struct edge { int from,to,val,next; }map[maxn]; int vis[maxn],que[maxn],dist[maxn],len; void init() //初始化 切记 { len=0; memset(vis,-1,sizeof(vis)); } void insert (int from,int to,int val) { map[len].from=from,map[len].to=to,map[len].val=val; map[len].next=vis[from]; vis[from]=len++; map[len].from=to,map[len].to=from,map[len].val=0; map[len].next=vis[to]; vis[to]=len++; } int Dinic(int n,int s,int t) { int ans=0; while(true) { int head,tail,id,i; head=tail=0; que[tail++]=s; memset(dist,-1,sizeof(dist)); dist[s]=0; while(head<tail) { id=vis[que[head++]]; while(id!=-1) { if(map[id].val>0&&dist[map[id].to]==-1) { dist[map[id].to]=dist[map[id].from]+1; que[tail++]=map[id].to; if(map[id].to==t) { head=tail; break; } } id=map[id].next; } } if(dist[t]==-1) break; id=s,tail=0; while(true) { if(id==t) //找到一条增广路 { int flow=INF,fir; for(i=0;i<tail;i++) if(map[que[i]].val<flow) { fir=i; flow=map[que[i]].val; } for(i=0;i<tail;i++) map[que[i]].val-=flow,map[que[i]^1].val+=flow; ans+=flow; tail=fir; id=map[que[fir]].from; } id=vis[id]; while(id!=-1) { if(map[id].val>0&&dist[map[id].from]+1==dist[map[id].to]) break; id=map[id].next; } if(id!=-1) { que[tail++]=id; id=map[id].to; } else { if(tail==0) break; dist[map[que[tail-1]].to]=-1; id=map[que[--tail]].from; } } } return ans; } //以上是纯模板 只要知道输入 Dinic 的三个int 是点数 起点 汇点 int main() { int n,i,j; int t; int sum; int D,W,k; int flag=0; scanf("%d",&t); while(t--) { memset(f,0,sizeof(f)); init(); flag=0; sum=0; scanf("%d",&n); for(i=1;i<=n;i++) { for(j=1;j<=7;j++) scanf("%d",&f[i][j]); scanf("%d%d",&D,&W); insert(0,i,D); //源点和电影部数相连 sum+=D; if(flag<W) flag=W; for(k=0;k<W;k++) for(j=1;j<=7;j++) if(f[i][j]) insert(i,7*k+j+n,1); //电影和各周中相应的天数相连,权值为1 } int T=n+7*flag+1; for(i=0;i<flag;i++) //将每个星期的周一到周日都和汇点相连 for(j=1;j<=7;j++) insert(7*i+n+j,T,1); int ans=Dinic(T+1,0,T); if(sum==ans) //如果需要的天数满流就YES printf("Yes\n"); else printf("No\n"); } return 0; }
我把代码折起来是希望看到思路的人自己回去敲一下!这样进步比较快!