题目
题意: 给定有向图,求出图中的所有关键边。
思路: 所谓的关键边,即增大这条边的边权之后能增大最大流的流量。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 502;
const int M = 2*(5002+N);
const ll INF = 1e18;
int q[N]; int d[N]; int cur[N];
int h[N],e[M],ne[M];
ll w[M]; //对应边的流量
ll f[M]; //对应边的容量
int idx = 0;
int in[N],out[N];
int st,ed,st2,ed2;
int n,m,k,T;
bool vis[N];
bool l[N],r[N];
void add(int a,int b,ll c)
{
e[idx] = b,w[idx] = c,f[idx] = c,ne[idx] = h[a],h[a] = idx++;
}
void dfs(int u,int wh)
{
if(wh==0) l[u] = 1;
else r[u] = 1;
vis[u] = 1;
for(int i=h[u];~i;i=ne[i])
{
int j = e[i];
if(!vis[j]&&w[i^wh]) //对应的正向边不满流.
{
dfs(j,wh);
}
}
}
bool bfs()
{
int hh = 0,tt = 0;
memset(d,-1,sizeof(d));
d[st] = 0,cur[st] = h[st],q[tt++] = st;
while(hh!=tt)
{
int u = q[hh++];
for(int i=h[u];~i;i=ne[i])
{
int j = e[i];
if(d[j]==-1&&w[i])
{
d[j] = d[u] + 1;
cur[j] = h[j];
if(j==ed) return true;
q[tt++] = j;
}
}
}
return 0;
}
ll find(int u,ll limit)
{
if(u==ed) return limit;
ll flow = 0;
for(int i=cur[u];~i&&flow<limit;i=ne[i])
{
cur[u] = i;
int j = e[i];
if(d[j]==d[u]+1&&w[i])
{
ll t = find(j,min(1ll*w[i],limit-flow));
if(!t) d[j] = -1;
flow += t; w[i] -= t,w[i^1] += t;
}
}
return flow;
}
ll dinic()
{
ll ans = 0,flow;
while(bfs()) while(flow = find(st,INF)) ans += flow;
return ans;
}
void solve()
{
memset(h,-1,sizeof(h));
scanf("%d%d",&n,&m);
st = 0,ed = n-1;
while(m--)
{
int a,b,c; scanf("%d%d%d",&a,&b,&c);
add(a,b,c),add(b,a,0);
}
ll ans = dinic();
// cout<<ans<<"??\n";
ll res = 0;
memset(vis,false,sizeof(vis));
dfs(st,0);
memset(vis,false,sizeof(vis));
dfs(ed,1);
for(int i=0;i<idx;i+=2)
{
if(w[i]==0)
{
int t2 = e[i];
int t1 = e[i^1];
if(l[t1]&&r[t2]) res++;
}
}
cout<<res;
}
signed main(void)
{
solve();
return 0;
}
/*
3 2 1 3
1 2 1000 2000
2 3 100 200
*/