path
题意:\(n\)个点\(m\)条边的有向图,需要砍掉几条边使从\(1\)到\(n\)的最短路变长,问花费的最小值。花费等于砍掉的所有边的权值和。
题解:两遍dij跑出所有属于\(1\)到\(n\)的最短路的边(边需要满足的条件为\(dis1[u]+w+dis2[v]==dis1[n]\),\(dis1\)以1为源点,\(dis2\)以n为源点).用这些边建图,对这个图跑最小割即可. 一道板题敲半天TUT
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int> pa;
const int maxn=20005;
int n,m;
const ll inf=0x3f3f3f3f;
struct node{
int v,nxt;
ll w;
}edge[maxn],edge2[maxn];
int head[maxn],cnt=0,head2[maxn],cnt2=0;
void add(int u,int v,ll w){
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].nxt=head[u];
head[u]=cnt++;
}
void add2(int u,int v,ll w){
edge2[cnt2].v=v;
edge2[cnt2].w=w;
edge2[cnt2].nxt=head2[u];
head2[u]=cnt2++;
}
ll dis[maxn];
bool bfs(){
if(n==1) return 0;
for(int i=1;i<=n;i++) dis[i]=-1;
queue<int> que;
que.push(1);
dis[1]=1;
while(!que.empty()){
int u=que.front();
que.pop();
for(int i=head2[u];~i;i=edge2[i].nxt){
int v=edge2[i].v;
if(edge2[i].w&&dis[v]<0){
//cout << u << " " << v << " " << edge2[i].w << '\n';
dis[v]=dis[u]+1;
que.push(v);
}
}
}
return dis[n]!=-1;
}
ll dinic(int now,ll w){
if(now==n) {
if(w==inf) return 0;
return w;
}
ll res=0;
for(int i=head2[now];~i;i=edge2[i].nxt){
int v=edge2[i].v;
if(edge2[i].w&&dis[v]==dis[now]+1){
ll tmp=dinic(v,min(edge2[i].w,w));
edge2[i].w-=tmp;
edge2[i^1].w+=tmp;
res += tmp;
if(res==w) return w;
}
}
return res;
}
void dij(int s){
bool vis[maxn];
memset(vis,0,sizeof(vis));
memset(dis,inf,sizeof(dis));
priority_queue<pa,vector<pa>,greater<pa> > que;
que.push(make_pair(0,s));
dis[s]=0;
while(!que.empty()){
int u=que.top().second;
que.pop();
if(vis[u]) continue;
vis[u]=true;
for(int i=head[u];~i;i=edge[i].nxt){
int v=edge[i].v;
ll w=edge[i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
que.push(make_pair(dis[v],v));
}
}
}
}
int input[maxn][3];
ll dis1[maxn],dis2[maxn];
int main(){
int T;
cin >> T;
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&input[i][0],&input[i][1],&input[i][2]);
}
for(int i=1;i<=n;i++) head[i]=-1;
cnt=0;
for(int i=1;i<=m;i++) add(input[i][1],input[i][0],input[i][2]);
dij(n);
memcpy(dis2,dis,sizeof(dis));
for(int i=1;i<=n;i++) head[i]=-1;
cnt=0;
for(int i=1;i<=m;i++){
add(input[i][0],input[i][1],input[i][2]);
}
dij(1);
memcpy(dis1,dis,sizeof(dis));
cnt2=0;
for(int i=1;i<=n;i++) head2[i]=-1;
for(int u=1;u<=n;u++){
for(int i=head[u];~i;i=edge[i].nxt){
int v=edge[i].v;
ll w=edge[i].w;
if(dis1[u]+w+dis2[v]==dis1[n]){
add2(u,v,w);
add2(v,u,0);
}
}
}
ll ans=0;
while(bfs()){
//cout << dis[n]<<'\n';
ans += dinic(1,inf);
}
printf("%lld\n",ans);
}
return 0;
}