Ikki’s Story I - Road Reconstruction
题意:找出图中“关键边”的条数,“关键边”:增加这条边的流量,源点s到汇点t的最大流量将增加。
思路:因为关键边一定是满流边(如果最开始都没用完,再增加这条边的流量肯定也用不上),所以我们跑完网络最大流后,直接判断这些满流边(即残量为0的边)是否满足:①源点s能否到达这条边的起点;②这条边的终点能否到达汇点t。满足这两点时,增加这条边的流量,最大流就肯定会增加。
注意:满流边不一定是关键边,因为可能会出现一条路径上有几条满流边的情况,这时候增加其中一条边的流量,这条路径上的最大流不会增加。
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<iomanip>
using namespace std;
typedef long long LL;
const int manx=1e4+1e3;
const int manx2=1e7+10;
const int mod=1e9+7;
const int INF=1e9;
const double inf=1e9+7;
int head[600],cur[600],deep[600],vs1[600],vs2[600];
int n,m,cou;//vs1记录源点s能到达的点//vs2记录能到达汇点t的点
int s=0,t;
struct node
{
int s,e,w,bf;
} edge[manx];
void add(int s,int e,int w)
{
edge[cou]=node{s,e,w,head[s]};
head[s]=cou++;
}
void init()
{
cou=0;
memset(head,-1,sizeof head);
memset(vs1,0,sizeof vs1);
memset(vs2,0,sizeof vs2);
}
int bfs()
{
memcpy(cur,head,sizeof cur);
memset(deep,-1,sizeof deep);
queue<int>qu;
qu.push(s);
deep[s]=0;
while(!qu.empty())
{
int now=qu.front();
qu.pop();
for(int i=head[now]; ~i; i=edge[i].bf)
{
int e=edge[i].e;
if(deep[e]==-1&&edge[i].w>0)
{
deep[e]=deep[now]+1;
qu.push(e);
}
}
}
return deep[t]!=-1;
}
int dfs(int now=s,int flow=INF)
{
if(now==t)
return flow;
int ans=0;
for(int i=cur[now]; ~i; i=edge[i].bf)
{
cur[now]=i;
int e=edge[i].e;
if(edge[i].w>0&&deep[e]==deep[now]+1)
{
int temp=dfs(e,min(flow,edge[i].w));
flow-=temp,ans+=temp;
edge[i].w-=temp;
edge[i^1].w+=temp;
if(!flow)
break;
}
}
return ans;
}
int Dinic()
{
int ans=0;
while(bfs())
ans+=dfs();
return ans;
}
void dfs1()
{
queue<int>qu;
qu.push(s);
vs1[s]=1;
while(!qu.empty())
{
int now=qu.front();
qu.pop();
for(int i=head[now];~i;i=edge[i].bf)
{
if(!vs1[edge[i].e]&&edge[i].w>0)
{
vs1[edge[i].e]=1;
qu.push(edge[i].e);
}
}
}
}
void dfs2()
{
queue<int>qu;
qu.push(t);
vs2[t]=1;
while(!qu.empty())
{
int now=qu.front();
qu.pop();
for(int i=head[now];~i;i=edge[i].bf)
{
if(!vs2[edge[i].e]&&edge[i^1].w>0)
{//这里和dfs1有一点不同,
//因为这里是看哪些点能到汇点t,所以要看反向边 i^1
vs2[edge[i].e]=1;
qu.push(edge[i].e);
}
}
}
}
int slove()
{
dfs1();
dfs2();
int ans=0;
for(int i=0;i<=m*2-1;i+=2)
if(edge[i].w==0&&vs1[edge[i].s]&&vs2[edge[i].e])
ans++;
return ans;
}
int main()
{
init();
int x,y,w,temp=0;
scanf("%d%d",&n,&m);
t=n-1;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&w);
if(w==0)
{
temp++;
continue;
}
add(x,y,w);
add(y,x,0);
}
m-=temp;//不知道有没有流量为0的边,就判断了一下
Dinic();
printf("%d\n",slove());
return 0;
}