poj1698 [ Usaco2007 Feb ] --最大流(Dinic)
题目大意:
爱丽丝要拍电影,有n部电影,规定爱丽丝每天只能拍一部电影,每部电影在每个礼拜只有固定的几天可以拍电影,只可以拍前面w个礼拜,并且这部电影要拍d天,问爱丽丝能不能拍完所有的电影。
思路:
建图。点1~350代表天数(因为最多只有350天),点351~370代表电影(最多只有20部电影)。从源点向每部电影连一条容量为d的边,从每部电影向可以拍摄它的那几天连一条容量为1的边,从每天向汇点连一条容量为1的边(限制每天只能拍一部电影)。再求一遍最大流,看其是否与sum(d[i])相等,如果是,就输出Yes,否则输出No。
具体看代码。
#include<iostream> #include<cstdio> #include<vector> #include<queue> #include<cstring> using namespace std; #define INF 2147483647 vector<int>g[400]; queue<int>q; struct Edge{ int to,from,cap,flow; }edge[160000]; int i,j,k,s,t,n,m,x,y,sum,w,d,cur[400],T,dist[400]; bool a[8],vis[400]; void addedge(int x,int y,int cap){ edge[m++]=(Edge){y,x,cap,0}; edge[m++]=(Edge){x,y,0,0}; g[x].push_back(m-2); g[y].push_back(m-1); } bool bfs(){ memset(vis,0,sizeof(vis)); vis[s]=1; dist[s]=0; q.push(s); while(!q.empty()){ int x=q.front();q.pop(); for(int i=0;i<g[x].size();i++){ Edge& e=edge[g[x][i]]; if(e.cap>e.flow&&!vis[e.to]){ vis[e.to]=1; dist[e.to]=dist[x]+1; q.push(e.to); } } } return vis[t]; } int dfs(int x,int a){ if(x==t||!a)return a; int flow=0,f; for(int& i=cur[x];i<g[x].size();i++){ Edge& e=edge[g[x][i]]; if(dist[x]+1==dist[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))){ e.flow+=f; edge[g[x][i]^1].flow-=f; flow+=f; a-=f; if(!a)break; } } return flow; } int maxflow(){ int flow=0; while(bfs()){ memset(cur,0,sizeof(cur)); flow+=dfs(s,INF); } return flow; } int main() { scanf("%d",&T); while(T--){ scanf("%d",&n); sum=m=0;t=351+n; for(i=1;i<=n;i++){ for(j=1;j<=7;j++)scanf("%d",&a[j]); scanf("%d%d",&d,&w); sum+=d; addedge(s,i+350,d); for(j=1;j<=7;j++) if(a[j])for(k=0;k<w;k++)addedge(i+350,k*7+j,1); } for(i=1;i<=350;i++)addedge(i,t,1); if(maxflow()==sum)printf("Yes\n");else printf("No\n"); for(i=0;i<=t;i++)g[i].clear(); } return 0; }