题意:从1点到n点,有多条路径,在路径上需要放置障碍物,花费最少,使得1->不通,这里的路径都是所有最短的路径
分析:这题本质上是个最小割边问题,直接跑最大流即可,但是这题要求的是最短路径上的最大流,我们可以先从n点预处理一下到每个点的最短距离,然后在增广的时候判断现在的点和下一个点是否满足d[now]=d[next]-1即可,这里由于都是由最短路径向前增广,所以不用考虑负向增广(ltx大佬解释)
代码:
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define mod 1000000007
#define lowbit(x) (x&(-x))
#define mem(a,b) memset(a,b,sizeof(a))
#define FRER() freopen("in.txt","r",stdin);
#define FREW() freopen("out.txt","w",stdout);
using namespace std;
typedef pair<int,int> pii;
const int maxn = 40000 + 7 , inf = 0x3f3f3f3f ;
int nxt[maxn],from[maxn],to[maxn],cap[maxn],head[maxn];
int d[maxn],d2[maxn],prv[maxn],inq[maxn];
int n,m,nEdge;
void addEdge(int u,int v,int c){
nxt[nEdge]=head[u],from[nEdge]=u,to[nEdge]=v,cap[nEdge]=c,head[u]=nEdge++;
nxt[nEdge]=head[v],from[nEdge]=v,to[nEdge]=u,cap[nEdge]=0,head[v]=nEdge++;
}
int bfs(int s){
mem(d2,inf);
queue<int>q;
q.push(s);
d2[s]=0;
while(!q.empty()){
int u = q.front();q.pop();
for(int e = head[u];~e;e=nxt[e]){
int v = to[e];
if(d2[v]!=inf)continue;
d2[v] = d2[u]+1;
q.push(v);
}
}
}
int EK(int s,int t){
int flow = 0;
while(1){
queue<int>q;
mem(d,0);
mem(inq,0);
d[s]=inf;
q.push(s);
while(!q.empty()){
int u = q.front();q.pop();
inq[u] = 0;
for(int e = head[u];~e;e=nxt[e]){
int v = to[e];
if(cap[e]&&!d[v]&&d2[v]==d2[u]-1){
prv[v] = e;
d[v] = min(d[u],cap[e]);
if(!inq[v]){
q.push(v);
inq[v] = 1;
}
}
}
if(d[t]) break;
}
if(!d[t]) break;
for(int u = t;u!=s;u=from[prv[u]]){
cap[prv[u]]-=d[t];
cap[prv[u]^1]+=d[t];
}
flow+=d[t];
}
return flow;
}
int main(){
// FRER();
int T;
scanf("%d",&T);
while(T--){
mem(head,-1);
nEdge = 0;
scanf("%d%d",&n,&m);
while(m--){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
addEdge(a,b,c);
addEdge(b,a,c);
}
bfs(n);
printf("%d\n",EK(1,n));
}
return 0;
}