POJ 3204 Ikki's Story I - Road Reconstruction
2010-12-11 23:35
316 查看
【题目大意】给定一个流网络,让你求其中有多少条有效边。其中有效边的定义是:修改这条边的容量,可以使最大流增大。(只允许修改一条边)
【算法分析】如果你平常写网络流不都是写预流推进的话,这题应该难不倒你。。。
实际上呢,如果你把某一条边的容量增加了的话,如果最大流增大,那么必然是在当前流网络中能找到一条新的增广路(并且该增广路要经过你修改过的那条边)。而最大流的标志则是不能再找到增广路了。
于是我们得到这样一个算法:
选求最大流。
然后在残余网络中找满流边[X,Y](如果是非满流边你增加它容量也没用。。。因为它的容量本来就过多了)
如果在残余网络中存在路径[S,X]和[Y,T],那么这条边为有效边。
为什么?
因为如果你增加[X,Y]的容量,那么在存在增广路径[S,X]->[X,Y]->[Y,T]
这样我们就得到一个求有效边的算法。
但是如果你要Floyed的话。。。我不阻止你。。。
而我们其实存在更高效的方法,那就是先以S为起点DFS,然后将所有边反向,然后以T为起点dfs。
这样总复杂度就是O(maxflow)
以上转自http://hi.baidu.com/edwardmj/blog/item/112891b73f289ac536d3ca80.html
代码:
【算法分析】如果你平常写网络流不都是写预流推进的话,这题应该难不倒你。。。
实际上呢,如果你把某一条边的容量增加了的话,如果最大流增大,那么必然是在当前流网络中能找到一条新的增广路(并且该增广路要经过你修改过的那条边)。而最大流的标志则是不能再找到增广路了。
于是我们得到这样一个算法:
选求最大流。
然后在残余网络中找满流边[X,Y](如果是非满流边你增加它容量也没用。。。因为它的容量本来就过多了)
如果在残余网络中存在路径[S,X]和[Y,T],那么这条边为有效边。
为什么?
因为如果你增加[X,Y]的容量,那么在存在增广路径[S,X]->[X,Y]->[Y,T]
这样我们就得到一个求有效边的算法。
但是如果你要Floyed的话。。。我不阻止你。。。
而我们其实存在更高效的方法,那就是先以S为起点DFS,然后将所有边反向,然后以T为起点dfs。
这样总复杂度就是O(maxflow)
以上转自http://hi.baidu.com/edwardmj/blog/item/112891b73f289ac536d3ca80.html
代码:
#include<iostream> using namespace std; const int inf=1<<30; const int MAX=505; struct node { int u,v,c,next; }g[250000]; int pre[MAX],cur[MAX],adj[MAX],num[MAX],dis[MAX],mat[MAX][MAX]; int v1[MAX],v2[MAX]; int s,t,e,cnt,n,m; void add(int u,int v,int c) { g[e].u=u; g[e].v=v; g[e].c=c; g[e].next=adj[u]; adj[u]=e++; g[e].u=v; g[e].v=u; g[e].c=0; g[e].next=adj[v]; adj[v]=e++; } void dfs1(int x) { v1[x]=1; for(int i=0;i<n;i++) { if(mat[x][i]&&!v1[i]) dfs1(i); } } void dfs2(int x) { v2[x]=1; for(int i=0;i<n;i++) { if(mat[x][i]&&!v2[i]) dfs2(i); } } void sap() { int u,v,i,aug=inf,flag; for(i=0;i<n;i++) { cur[i]=adj[i]; dis[i]=num[i]=0; } num[0]=n; u=s; while(dis[s]<n) { flag=0; for(i=cur[u];i!=-1;i=g[i].next) { v=g[i].v; if(g[i].c>0&&dis[u]==dis[v]+1) { flag=1; cur[u]=i; pre[v]=u; aug=min(aug,g[i].c); u=v; if(u==t) { while(u!=s) { u=pre[u]; g[cur[u]].c-=aug; g[cur[u]^1].c+=aug; } aug=inf; u=s; } break; } } if(flag) continue; if(--num[dis[u]]==0) return; dis[u]=inf; for(i=adj[u];i!=-1;i=g[i].next) { if(g[i].c>0&&dis[g[i].v]<dis[u]) { dis[u]=dis[g[i].v]; cur[u]=i; } } dis[u]++; num[dis[u]]++; if(u!=s) u=pre[u]; } } int main() { int a,b,c; scanf("%d%d",&n,&m); e=0; memset(adj,-1,sizeof(adj)); s=0; t=n-1; while(m--) { scanf("%d%d%d",&a,&b,&c); add(a,b,c); } sap(); //cout<<"yes"<<endl; for(a=0;a<=e;a+=2) { if(g[a].c>0) mat[g[a].u][g[a].v]=1; } dfs1(s); memset(mat,0,sizeof(mat)); for(a=0;a<=e;a+=2) { if(g[a].c>0) mat[g[a].v][g[a].u]=1; } dfs2(t); cnt=0; for(a=0;a<e;a+=2) { if(g[a].c==0&&v1[g[a].u]&&v2[g[a].v]) cnt++; } cout<<cnt<<endl; return 0; }
相关文章推荐
- poj 3204 Ikki's Story I - Road Reconstruction(最小割,求关键边)
- poj 3204 Ikki's Story I - Road Reconstruction && zoj 2532 Internship 网络流关键边
- POJ 3204 Ikki's Story I - Road Reconstruction 最大流关键边
- POJ 3204 Ikki's Story I - Road Reconstruction(最小割+残余网络)
- 【POJ 3204】Ikki's Story I - Road Reconstruction
- POJ 3204 Ikki's Story I - Road Reconstruction(最大流-Dinic)
- poj 3204 Ikki's Story I - Road Reconstruction(最大流求割边)
- POJ 3204 Ikki's Story I - Road Reconstruction 残余网络
- poj 3204 Ikki's Story I - Road Reconstruction 最大流
- poj 3204 Ikki's Story I - Road Reconstruction 找可使流量增加的割边个数 最小割+dfs
- poj 3204 Ikki's Story I - Road Reconstruction
- 【POJ】3204 Ikki's Story I - Road Reconstruction 最大流
- POJ 3204 - Ikki's Story I - Road Reconstruction 找最小割的割边数量
- poj 3204 Ikki's Story I - Road Reconstruction(最大流割边)
- POJ-3204-Ikki's Story I - Road Reconstruction
- poj 3207 Ikki's Story IV - Panda's Trick 2-sat
- [POJ 3207]Ikki's Story IV - Panda's Trick(2-SAT入门题)
- POJ 3207 Ikki's Story IV - Panda's Trick(2-sat)
- POJ-3207-Ikki's Story IV - Panda's Trick(2-sat模板)
- 【POJ】3207 Ikki's Story IV - Panda's Trick 2-sat