本文主要是介绍poj1698-网络流,(Ek)和(Dinic)算法。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
题目连接
开始学习网络流了,刚开就做这道题,确实不知道这么建图。
发现网络流建图很重要,图建好了,问题就好解决了,这题确实建图有难度。
点击打开链接
看下这张草图:
按着实际意思:应该为左边的图,(是个多源节点和多个汇点的网络),可以转化成单源节点和单源汇点的问题。方法就是:添加一个超级源节点和超级汇点。如图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; }
这篇关于poj1698-网络流,(Ek)和(Dinic)算法。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!