|
Posted on 2010-10-06 11:53 成幸毅 阅读(321) 评论(0) 编辑 收藏 引用
题目意思是要求边有扩容之后能使流量加大,问这样的边有几条,这里要注意的是,最小割不一定就是这种边,但是这种边就一定是割了,因为假设可能有一条增光路上有和最小割相同容量的边,那么扩容了最小割也没用,所以一次DFS正向反向都不行,必须两次DFS。正的来一次,反向图从汇点来一次,标记1,2然后连接1和2的那条边就是可扩容边。假设x-.y是可扩容边,那么必定有,s->x和y->t存在。
【题目大意】

给出一张传输流量图,求给哪些边添加容量,可以增大最大流。
【解题思路】

实际上就是求割边,但这个割边必需是一头能被源到达,另一头能被汇到达。

【Code】

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;

#define MAXN 510
#define MAXM 10010
#define inf 1000000000


struct Edge
  {
int to, from, flow, cap;
int next, pair; //pair表示跟它是一对的另一边
};

int n, m;
int source, sink; //源点和汇点
Edge edge[MAXM];
int cnt, pn[MAXN];

void addedge(int from, int to, int cap) //一次增加两条边
  {
edge[cnt].from = from;
edge[cnt].to = to;
edge[cnt].next = pn[from];
edge[cnt].cap = cap;
edge[cnt].flow = 0;
edge[cnt].pair = cnt + 1;
pn[from] = cnt++;

//增加另一条边
edge[cnt].from = to;
edge[cnt].to = from;
edge[cnt].next = pn[to];
edge[cnt].cap = 0;
edge[cnt].flow = 0;
edge[cnt].pair = cnt - 1;
pn[to] = cnt++;
}

int numb[MAXN],dist[MAXN],curedge[MAXN],pre[MAXN];


int ISAP()
  {
int cur_flow,max_flow,u,tmp,neck,i;
memset(dist,0,sizeof(dist));
memset(numb,0,sizeof(numb)); //初始化为0,不需要反向bfs了
for(i = 1 ; i <= n ; ++i)
curedge[i] = pn[i];
numb[n] = n;
max_flow = 0;
u = source;
while(dist[source] < n)
 {
if(u == sink)
 {
cur_flow = inf + 1; //!!!!注意这里要大于inf
for(i = source; i != sink; i = edge[curedge[i]].to)
if(cur_flow > edge[curedge[i]].cap)
 {
neck = i;
cur_flow = edge[curedge[i]].cap;
}
for(i = source; i != sink; i = edge[curedge[i]].to)
 {
tmp = curedge[i];
edge[tmp].cap -= cur_flow;
edge[tmp].flow += cur_flow;
tmp = edge[tmp].pair;
edge[tmp].cap += cur_flow;
edge[tmp].flow -= cur_flow;
}
max_flow += cur_flow;
u = neck;
}
for(i = curedge[u]; i != -1; i = edge[i].next)
if(edge[i].cap > 0 && dist[u] == dist[edge[i].to]+1)
break;
if(i != -1)
 {
curedge[u] = i;
pre[edge[i].to] = u;
u = edge[i].to;
}
else
 {
if(0 == --numb[dist[u]])
break;
curedge[u] = pn[u];
for(tmp = n,i = pn[u]; i != -1; i = edge[i].next)
if(edge[i].cap > 0)
tmp = tmp<dist[edge[i].to]?tmp:dist[edge[i].to];
dist[u] = tmp + 1;
++numb[dist[u]];
if(u != source)
u = pre[u];
}
}
return max_flow;
}

int mat[MAXN][MAXN];
bool vs[MAXN],vt[MAXN];

void dfs(int k, bool v[MAXN]) //求从k出发可以到达的所有顶点
  {
int i;
v[k] = 1;
for (i = 1; i <= n; i++)
if (!v[i] && mat[k][i])
dfs(i, v);
}

void work()
  {
int i;
memset(mat,0,sizeof(mat));

for (i = 1; i < cnt; i += 2)
 {
if (edge[i].cap) //非满流边
 {
mat[edge[i].from][edge[i].to] = 1;
}
}
memset(vs,0,sizeof(vs));
dfs(source, vs); //从0开始搜索
memset(mat,0,sizeof(mat));
for (i = 1; i < cnt; i += 2)
 {
if (edge[i].cap)
 {
mat[edge[i].to][edge[i].from] = 1;
}
}
memset(vt,0,sizeof(vt));
dfs(sink,vt); //从n-1开始搜索

int ans = 0;
for (i = 1; i < cnt; i += 2)
 {
if (!edge[i].cap && vs[edge[i].from] && vt[edge[i].to])
ans++;
}
printf("%d\n",ans);
}


int main()
  {
int u, v, w;
// freopen("in.txt","r",stdin);
scanf("%d %d",&n,&m);
memset(pn,0xff,sizeof(pn));
cnt = 1;
while (m--)
 {
scanf("%d %d %d",&u,&v,&w);
u++;
v++;
addedge(u,v,w);
}
source = 1;
sink = n;
u = ISAP();
work();
return 0;
}

|