开始学习网络流了,刚开就做这道题,确实不知道这么建图。
发现网络流建图很重要,图建好了,问题就好解决了,这题确实建图有难度。
看下这张草图:
按着实际意思:应该为左边的图,(是个多源节点和多个汇点的网络),可以转化成单源节点和单源汇点的问题。方法就是:添加一个超级源节点和超级汇点。如图s 和 节点。
EK算法:(391ms)
#include<cstdio> #include<cstring> #include<queue> #define INF 0x3f using namespace std; const int N=375; int cap[N][N],f[N][N],w[51][8]; //cap表示容量,f表示留流量。 int pre[N],rec[N]; int n,m,r,ans; bool BFS() //寻找增广路 { int i,j; queue<int>Q; memset(rec,0,sizeof(rec)); pre[0]=-1; rec[0]=INF; Q.push(0); while(!Q.empty()){ i=Q.front(); Q.pop(); for(j=1;j<=r;j++){ if(cap[i][j]>f[i][j]&&!rec[j]){ rec[j]=rec[i]; if(cap[i][j]-f[i][j]<rec[j]) rec[j]=cap[i][j]-f[i][j]; pre[j]=i; Q.push(j); if(j==r) return true; } } } return false; } void EK() { while(BFS()){ //当找不到增广路,就代表当前的网络流是最大流了。 for(int i=r;i!=0;i=pre[i]){ f[pre[i]][i]+=rec[r]; // 修改流量 f[i][pre[i]]=-f[pre[i]][i]; //修改方向 } ans+=rec[r]; //只关心流入汇点的值。 } } int main() { int i,j,k,deadline[51],sum,d,t; scanf("%d",&t); while(t--){ scanf("%d",&n); memset(f,0,sizeof(f)); memset(cap,0,sizeof(cap)); m=-1,sum=0; for(i=1;i<=n;i++){ for(j=1;j<=7;j++) scanf("%d",&w[i][j]); scanf("%d%d",&d,&deadline[i]); cap[0][i]=d; if(deadline[i]>m) m=deadline[i]; sum+=d; } r=n+m*7+1; //超级汇点。 for(i=1;i<=n;i++) for(j=1;j<=deadline[i];j++){ for(int k=1;k<=7;k++){ if(w[i][k]){ cap[i][n+(j-1)*7+k]=1; //电影与日期 cap[n+(j-1)*7+k][r]=1; //每天日期对应汇点 } } } ans=0; EK(); if(ans==sum) puts("Yes"); else puts("No"); } return 0; }
Dinic算法:(47ms)#include<cstdio> #include<queue> #include<cstring> #define INF 0x3f #define min(a,b) a<b?a:b using namespace std; const int N=372; int rec[N][10],cap[N][N],dis[N]; int s,t,n; void set_graph() { for(int i=1;i<=n;i++){ cap[0][i+350]=rec[i][8]; for(int j=1;j<=7;j++){ if(rec[i][j]){ for(int k=0;k<rec[i][9];k++){ cap[i+350][j+k*7]=1; } } } } for(int i=1;i<=350;i++) cap[i][371]=1; } bool BFS() { int i; queue<int>Q; memset(dis,-1,sizeof(dis)); dis[t]=0; Q.push(t); while(!Q.empty()){ i=Q.front(); Q.pop(); for(int k=0;k<N;++k){ if(dis[k]==-1&&cap[k][i]){ dis[k]=dis[i]+1; Q.push(k); } } if(i==s) return true; } return false; } int DFS(int cur,int h) { if(cur==t) return h; int tmp=h,t; for(int i=0;i<N&&tmp;i++){ if((dis[i]+1==dis[cur])&& cap[cur][i]){ t=DFS(i,min(cap[cur][i],tmp)); cap[cur][i]-=t; cap[i][cur]+=t; tmp-=t; } } return h-tmp; } int dinic() { int maxflow=0; while(BFS()){ maxflow+=DFS(s,INF); } return maxflow; } int main() { int sum,T; scanf("%d",&T); while(T--){ scanf("%d",&n); sum=0,s=0,t=371; memset(cap,0,sizeof(cap)); for(int i=1;i<=n;i++){ for(int j=1;j<=9;j++) scanf("%d",&rec[i][j]); sum+=rec[i][8]; } set_graph(); if(dinic()==sum) puts("Yes"); else puts("No"); } return 0; }