hdu4975--dinic算法(1)
来源:互联网 发布:深圳公务员 知乎 编辑:程序博客网 时间:2024/05/21 07:58
好像还能用isap和矩阵dp的,不过我没咋闹明白isap,分层能看懂后面就完全看不懂了,等今天晚上看懂了在写一个用isap做这道题的方法。嗯,立flag;
题意:给出 行数m和列数n,和各行各列的和,求这个矩阵可能的排列,不同的结果不同的输出,我都写到注释上面了。
方法:dinic,就是ek算法的增强版,先以源点为0,然后对整个网络进行分层,一层一层的分,分完层在进行dfs,跑一个while,不断的对残余网络分层,搜索,知道分层分不了了,也就是说到不了终点了就完事。
思路是不难理解的,见图的思路很值得学习,
注意点1 有一个弧优化,就是在进行dfs的时候,这样dfs就可以用while了,试想dfs的对树的搜索,如果用这个方法,就可以在达到目的之前对 左,中,右进行遍历。不然只会返回一个结果,
2 在对 残残残残残余网络之后见图 在判断 路径的大小,这样就会很省时间
#include <queue>#include <vector>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <iostream>#include <algorithm>#include <functional>const int maxn=2000;using namespace std;typedef long long ll;struct edge{int to,cap,rev;edge(int a,int b,int c){to=a,cap=b,rev=c;}//分别是目的地,记录反向边的坐标,和容量;};vector<edge>G[maxn];vector<int>G1[maxn];bool vis[maxn];int cengci[maxn];int n,m;int itr[maxn];void addedge(int from,int to,int value){ G[from].push_back((edge){to,value,G[to].size()}); G[to].push_back((edge){from,0,G[from].size()-1});}void add_edge(int from,int to){ G1[from].push_back(to);}void bfs(int s){ queue<int>q; q.push(s); memset(cengci,-1,sizeof(cengci)); cengci[s]=0;//这和上面一行都是分层必要的初始化; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=0;i<G[u].size();i++) { edge &s=G[u][i]; if(cengci[s.to]<0&&s.cap>0) {cengci[s.to]=cengci[u]+1;//分层; q.push(s.to);} } }}int dfs(int s,int t,int f){ //int flow; if(s==t) return f;//dfs结束的条件 for(int &i=itr[s];i<G[s].size();i++) { edge &w=G[s][i]; if(w.cap>0&&cengci[w.to]>cengci[s]) { int d=dfs(w.to,t,min(w.cap,f)); if(d>0) { w.cap-=d; G[w.to][w.rev].cap+=d;//反向边,自己画一个二维数组就理解了。g就是二位数组。 return d; } } }return 0;}int max_flow(int s,int t){ int INF=0x3f3f3f3f;int flow=0;int cas=1; while(1) { bfs(s); memset(itr,0,sizeof(itr)); if(cengci[t]<0) { //printf("%d!!! %d\n",t,cengci[t]); //printf("%d!!!!\n",cas++); return flow;} int l;//=dfs(s,t,INF); while(l=dfs(s,t,INF))//多次进行dfs,而不是一次分层然后一次dfs, flow+=l; }}bool judge_dfs(int x,int val){ vis[x]=1; for(int i=0;i<G1[x].size();i++) { int t=G1[x][i]; if(t==val) continue;//不找反向边。反向边一定能成为环所以你在逗我?? if(vis[t]) return 1;//确定已经找到环了,因为vis被预定就是说明是环了 if(judge_dfs(t,x)) return 1;//继续dfs,把后继节点的t变成左边的x,这样在下一个dfs中如果t==val就是说明 //他的后继节点是前驱结点,所以就是环咯。 } vis[x]=0; return 0;}bool judge(){ memset(vis,0,sizeof(vis)); for(int i=0;i<=m+n+1;i++) { for(int j=0;j<G[i].size();j++) {edge &e=G[i][j]; if(e.cap>0)//你看你看,如果在残余网络中边还存在,那么就见图,新建的图已经找不到一条增广路径了555; add_edge(i,e.to);} } for(int i=0;i<=n;i++) if(judge_dfs(i,-1)) return 1;//第二个参数设定成多少都行,只要不在 点的范围里。。就是钦定的边,就是说,如果判断某个具体的点能不能 //构成环。 return 0;}int main(){ int T; int a,b,t=1; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=0;i<maxn;i++) { G[i].clear(); G1[i].clear(); } int sum1=0,sum2=0,sum=0; for(int i=1;i<=n;i++) {scanf("%d",&a); addedge(0,i,a); sum+=a,sum1+=a;//把所有杭上的点给加了 //也就是左边的原点到左边一排的最大流。 } for(int j=n+1;j<=m+n;j++) { scanf("%d",&a); addedge(j,m+n+1,a); sum2+=a;//右边的最大流; } if(sum1!=sum2) {printf("Case #%d: So naive!\n",t++);//不能成立,数据有问题啊哈哈 continue; } for(int i=1;i<=n;i++) for(int j=1+n;j<=m+n;j++) { addedge(i,j,9); } int ans=max_flow(0,m+n+1); //printf("%d %d*******\n",ans,sum); if(ans!=sum) printf("Case #%d: So naive!\n",t++);//最大流跑不到和,不能成立。 else { if(judge()) printf("Case #%d: So young!\n",t++);//好多种类方法。 //在这个图中 //这个图表示的意思 就是各个行和和列和相互制约关系的成立。 //而这个图中有环,就说明了把每个边权加一个少一个都是没关系的。这部就有多种情况了嘛。 else printf("Case #%d: So simple!\n",t++);//只有一种情况,费了好大劲做出来。-。-好简单啊。 } } return 0;}
0 0
- hdu4975--dinic算法(1)
- hdu4975(最大流判环)
- 网络流(Dinic算法)
- 网络流(dinic算法)
- Dinic算法(最大流)
- Dinic 算法
- 【算法】dinic
- ((dinic)算法。。
- Dinic算法
- Dinic算法
- DINIC算法
- dinic算法
- 网络流模版(Dinic算法)
- hdu 3572 Task Schedule (dinic算法)
- 最大流模板(Dinic算法)
- Dinic算法(网络流,最大流)
- HDU 4280 (网络流Dinic算法)
- 网络流DINIC算法(模板)
- 使用Jersey开发RESTful服务
- 动态链接之可执行文件的装载与进程
- NodeJs学习笔记(一)
- JAVA之路
- hadoop Spark源码编译所需要的环境
- hdu4975--dinic算法(1)
- UNIX网络编程-listen函数及其包裹函数介绍
- 浏览器主页被更改成7654主页
- 团体程序设计天梯赛-练习集 L2-014. 列车调度 解题报告
- 面向对象特性
- 微服务架构模式简介
- cordova 安装及使用
- Java 垃圾回收和注意事项
- 探索并发编程(三)------Java存储模型和共享对象