题意:问加哪些边容量增大能够增加整体流量。
很显然,增加单个边容量改变全局容量,一遍最大流之后,这些边只有可能出现在满流的边内,而且是一条路中唯一的一条满流边。
题解: 大众解法,一遍最大流之后,整个图跑残了,记录那些满流的边,从起点开始深搜,只走非满流边,从终点开始搜,只走非满流边,如果某条满流边起始点被起点标记,且终止点被终点标记,那么这条满流边存在于有且仅有他自己的从起点到终点的非满流路线中。这条边为关键边,Num++;
我的做法:既然一遍最大流之后 ,整个图跑残了,如果将某些关键边进行添加流量操作,将会重新出现一条从起点到终点的通路,我们可以直接在残余网络中加流,然后进行从起点到终点的广搜,如果可以到达 num ++,思路简单,但是由于多次广搜,如果用普通队列实现dinic会超时,虽然用数组模拟队列很不好,但是表示这样确实很省时间。
代码:
#include<stdio.h>
#include<iostream>
#include<queue>
#define INF 1000000000
#define N 1005
#define M 10005
using namespace std;
int tot, list[N], deep[N], n, m, q[2000005];
struct Node
{
int date, value, next, from;
}cun[2000005];
struct dian
{
int x, t;
}old,xin;
void add(int a, int b, int c)
{
cun[++tot].value = c;
cun[tot].date = b;
cun[tot].next = list[a];
cun[tot].from = a;
list[a] = tot;
cun[++tot].value = 0;
cun[tot].date = a;
cun[tot].next = list[b];
cun[tot].from = b;
list[b] = tot;
}
int BFS(int s,int t)
{
int i,x,v,tail=0,head=0;
memset(deep,255,sizeof(deep));
deep[s]=0;
q[tail++]=s;
while(head<tail)
{
x=q[head++];
for(i=list[x];i;i=cun[i].next)
{//printf("!\n");
if(cun[i].value&&deep[v=cun[i].date]==-1)
{
deep[v]=deep[x]+1;
if(v==t)
return 1;
q[tail++]=v;
}
}
}
return 0;
}
int mmin(int a,int b)
{
if(a<b) return a;
else return b;
}
int DFS(int s,int t,int min)
{
if(s==t) return min;
int neww=0;
for(int k=list[s];k;k=cun[k].next)
{
int c=cun[k].value;
int date=cun[k].date;
if(c==0||deep[date]!=deep[s]+1) continue;
int m=DFS(date,t,mmin(c,min-neww));
neww+=m;
cun[k].value-=m;
cun[k^1].value+=m;
if(neww==min) break;
}
if(neww==0) deep[s]=0;
return neww;
}
int dinic(int s,int t,int n)
{
int num=0;
while(BFS(s,t))
{
num+=DFS(s,t,INF);
}
return num;
}
void bulid()
{
int a, b, c;
for(int i = 0; i < m; i++ )
{
scanf("%d %d %d",&a, &b, &c);
add(a+1, b+1, c);
}
int k = dinic(1, n, n+5);
int num = 0;
for(int i = 2; i <= tot; i += 2)
{
if(!cun[i].value)
{
cun[i].value += 1;
if(BFS(1, n)) num++;
cun[i].value -= 1;
}
}
printf("%d\n",num);
}
int main()
{
while(scanf("%d%d",&n, &m)!=EOF)
{
memset(list,0,sizeof(list));
tot = 1;
bulid();
}
}
很显然,增加单个边容量改变全局容量,一遍最大流之后,这些边只有可能出现在满流的边内,而且是一条路中唯一的一条满流边。
题解: 大众解法,一遍最大流之后,整个图跑残了,记录那些满流的边,从起点开始深搜,只走非满流边,从终点开始搜,只走非满流边,如果某条满流边起始点被起点标记,且终止点被终点标记,那么这条满流边存在于有且仅有他自己的从起点到终点的非满流路线中。这条边为关键边,Num++;
我的做法:既然一遍最大流之后 ,整个图跑残了,如果将某些关键边进行添加流量操作,将会重新出现一条从起点到终点的通路,我们可以直接在残余网络中加流,然后进行从起点到终点的广搜,如果可以到达 num ++,思路简单,但是由于多次广搜,如果用普通队列实现dinic会超时,虽然用数组模拟队列很不好,但是表示这样确实很省时间。
代码:
#include<stdio.h>
#include<iostream>
#include<queue>
#define INF 1000000000
#define N 1005
#define M 10005
using namespace std;
int tot, list[N], deep[N], n, m, q[2000005];
struct Node
{
int date, value, next, from;
}cun[2000005];
struct dian
{
int x, t;
}old,xin;
void add(int a, int b, int c)
{
cun[++tot].value = c;
cun[tot].date = b;
cun[tot].next = list[a];
cun[tot].from = a;
list[a] = tot;
cun[++tot].value = 0;
cun[tot].date = a;
cun[tot].next = list[b];
cun[tot].from = b;
list[b] = tot;
}
int BFS(int s,int t)
{
int i,x,v,tail=0,head=0;
memset(deep,255,sizeof(deep));
deep[s]=0;
q[tail++]=s;
while(head<tail)
{
x=q[head++];
for(i=list[x];i;i=cun[i].next)
{//printf("!\n");
if(cun[i].value&&deep[v=cun[i].date]==-1)
{
deep[v]=deep[x]+1;
if(v==t)
return 1;
q[tail++]=v;
}
}
}
return 0;
}
int mmin(int a,int b)
{
if(a<b) return a;
else return b;
}
int DFS(int s,int t,int min)
{
if(s==t) return min;
int neww=0;
for(int k=list[s];k;k=cun[k].next)
{
int c=cun[k].value;
int date=cun[k].date;
if(c==0||deep[date]!=deep[s]+1) continue;
int m=DFS(date,t,mmin(c,min-neww));
neww+=m;
cun[k].value-=m;
cun[k^1].value+=m;
if(neww==min) break;
}
if(neww==0) deep[s]=0;
return neww;
}
int dinic(int s,int t,int n)
{
int num=0;
while(BFS(s,t))
{
num+=DFS(s,t,INF);
}
return num;
}
void bulid()
{
int a, b, c;
for(int i = 0; i < m; i++ )
{
scanf("%d %d %d",&a, &b, &c);
add(a+1, b+1, c);
}
int k = dinic(1, n, n+5);
int num = 0;
for(int i = 2; i <= tot; i += 2)
{
if(!cun[i].value)
{
cun[i].value += 1;
if(BFS(1, n)) num++;
cun[i].value -= 1;
}
}
printf("%d\n",num);
}
int main()
{
while(scanf("%d%d",&n, &m)!=EOF)
{
memset(list,0,sizeof(list));
tot = 1;
bulid();
}
}