【题目】
【题解】
题意:给定一个有向图,删掉一些边,边权作为代价,使得最短路长度增加,输出最小总代价。
思路:先用Dijkstra算法求最短路,两个反向图跑出所有满足d(1,u)+w(u,v)+d(v,n)=d(1,n)的边并建图,d(a,b)为从a到b的最短路,再用Dinic算法在新图上求1和n的最小割。
【代码】
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define P pair<ll, int>
const int maxn=1e4+50;
const ll inf=0x3f3f3f3f3f3f3f3f;
struct node{
int u,v,nxt;
ll f;
}e[maxn*10];
int n,m,cnt=0;
int head[maxn];
int st,ed,ex;
vector <P> g1[maxn],g2[maxn];
ll dis1[maxn],disn[maxn];
priority_queue < P,vector<P>,greater<P> > Q;
int cur[maxn],dep[maxn];
int q[maxn*2];
int tot,tail;
void add(int u,int v,ll f)
{
e[cnt].u=u;
e[cnt].v=v;
e[cnt].f=f;
e[cnt].nxt=head[u];
head[u]=cnt++;
e[cnt].u=v;
e[cnt].v=u;
e[cnt].f=0;
e[cnt].nxt=head[v];
head[v]=cnt++;
}
void dij(int S,ll *dis,vector <P> *g)
{
for(int i=0;i<=n;i++) dis[i]=inf;
dis[S]=0;
while(Q.size()) Q.pop();
Q.push(P(dis[S],S));
while(Q.size()){
P temp=Q.top(); Q.pop();
int u=temp.second;
if(dis[u]<temp.first) continue;
for(int i=0;i<g[u].size();i++){
int v=g[u][i].second;
ll w=g[u][i].first;
if(dis[u]+w<dis[v]){
dis[v]=dis[u]+w;
Q.push(P(dis[v],v));
}
}
}
}
bool bfs()
{
memset(dep,-1,(ex+1)<<2);
dep[st]=1;
q[tot=0]=st,tail=1;
while(tot<tail){
int u=q[tot++];
if(u==ed) break;
for(int i=head[u];~i;i=e[i].nxt){
int v=e[i].v;
if(dep[v]!=-1||!e[i].f) continue;
dep[v]=dep[u]+1;
q[tail++]=v;
}
}
return dep[ed]!=-1;
}
ll dfs(int u,ll flow)
{
ll res=flow;
if(u==ed) return flow;
for(int &i=cur[u];~i;i=e[i].nxt){
int v=e[i].v;
if(dep[v]!=dep[u]+1||!e[i].f) continue;
ll d=dfs(v,min(res,e[i].f));
e[i].f-=d;
e[i^1].f+=d;
res-=d;
if(res==0) break;
}
if(flow==res) dep[u]=-1;
return flow-res;
}
ll dinic()
{
ll ans=0;
ll d;
while(bfs()){
for(int i=0;i<=ex;i++)
cur[i]=head[i];
while(d=dfs(st,inf))
ans+=d;
}
return ans;
}
int main()
{
int t; scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
cnt=0;
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++)
g1[i].clear(),g2[i].clear();
while(m--){
int u,v; ll w;
scanf("%d%d%lld",&u,&v,&w);
g1[u].push_back(P(w,v));
g2[v].push_back(P(w,u));
}
dij(1,dis1,g1);
dij(n,disn,g2);
if(dis1[n]==inf){
puts("0");
continue;
}
for(int u=1;u<=n;u++){
for(int i=0;i<g1[u].size();i++){
int v=g1[u][i].second;
ll w=g1[u][i].first;
if(dis1[u]+disn[v]+w==dis1[n])
add(u,v,w);
}
}
st=1,ed=n,ex=n+1;
printf("%lld\n",dinic());
}
return 0;
}