您的位置:首页 > 其它

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

代码:

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: