题意:
给一个有向图,删除每一条边的代价是边的长度,要求花费最小的代价,使得 1→n最短路变长,求该最小花费。
思路:
要使得最短路变长,那么删除的边一定要破坏原来的最短路。即要先把所有最短路的所有边找出来,通过删除某几条边,使得所有的最短路无效。
如何把最短路的所有边全部找出呢?以 dis1[i] 表示原图中, 1 号节点到其余节点的最短距离;以 dis2[i] 表示反向建图后 n 号节点到各节点的最小距离。如果一条边是最短路径上的边,假设两端点为 u 和 v,边权为 w,则有:
dis1[u]+w+dis2[v]=dis1[n]
所以在正向和反向建图跑两遍最短路后,遍历所有边就可以求出。
接下来在有这些边建成的图上删除边,使得 1 和 n 号点不连通。显然就是求最小割。
理论上 Dinic 的时间复杂度是 O(n2∗m),但实际上要优的多。
AC代码:
#include <bits/stdc++.h>//把所有最短路的所有边找出,然后跑最大流
using namespace std;
typedef long long ll;
typedef pair<ll,int> P;
const int N=1e4+5;
const ll inf=1e16;//注意取值范围设置合理的inf,WA的好惨
struct edge
{
int from;
int too;
ll val;
};
struct node
{
int to;
ll val;
int rev;
};
vector<P>pic[2][N];//正向和反向边
vector<edge>eg;//存边
vector<node>pa[N];//网络流的图
priority_queue<P,vector<P>,greater<P> >que;
queue<int>q;
ll dis[2][N];
int layer[N],iter[N];
int n;
void init()
{
for(int j=0;j<2;j++)
{
for(int i=0;i<=n;i++)
pic[j][i].clear();
for(int i=0;i<=n;i++)
dis[j][i]=inf;
}
eg.clear();
for(int i=0;i<=n;i++)
pa[i].clear();
}
void dij(int s)
{
while(!que.empty())
que.pop();
if(s==0)
{
que.push(make_pair(0,1));
dis[s][1]=0;
}
else
{
que.push(make_pair(0,n));
dis[s][n]=0;
}
while(!que.empty())
{
P now=que.top();
que.pop();
if(now.first>dis[s][now.second])
continue;
for(int i=0;i<pic[s][now.second].size();i++)
{
P tmp=pic[s][now.second][i];
if(tmp.first+dis[s][now.second]<dis[s][tmp.second])
{
dis[s][tmp.second]=tmp.first+dis[s][now.second];
que.push(make_pair(dis[s][tmp.second],tmp.second));
}
}
}
}
void addedge(int u,int v,ll w)
{
pa[u].push_back(node{v,w,pa[v].size()});
pa[v].push_back(node{u,0,pa[u].size()-1});
}
bool bfs()
{
while(!q.empty())
q.pop();
fill(layer,layer+n+1,-1);
layer[1]=0;
q.push(1);
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=0;i<pa[now].size();i++)
{
node t=pa[now][i];
if(layer[t.to]<0&&t.val>0)
{
layer[t.to]=layer[now]+1;
q.push(t.to);
if(t.to==n)
return true;
}
}
}
return false;
}
ll dfs(int v,ll w)
{
if(v==n)
return w;
for(int &i=iter[v];i<pa[v].size();i++)
{
node &e=pa[v][i];//cout<<"val="<<e.val<<endl;
if(e.val>0&&layer[e.to]>layer[v])
{
ll d=dfs(e.to,min(w,e.val));
if(d>0)
{
e.val-=d;
pa[e.to][e.rev].val+=d;
return d;
}
}
}
return 0;
}
ll dinic()
{
ll maxflow=0;
while(bfs())
{
ll f=0;
fill(iter,iter+1+n,0);
while((f=dfs(1,inf))>0)
maxflow+=f;//,cout<<"f="<<f<<endl;
}
return maxflow;
}
int main()
{
int t,m;
scanf("%d",&t);
while(t--)
{
int u,v;
ll w;
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=m;i++)
{
scanf("%d%d%lld",&u,&v,&w);
pic[0][u].push_back(make_pair(w,v));
pic[1][v].push_back(make_pair(w,u));
eg.push_back(edge{u,v,w});
}
dij(0);
dij(1);
for(int i=0;i<eg.size();i++)
{
if(dis[0][eg[i].from]+dis[1][eg[i].too]+eg[i].val==dis[0][n])
addedge(eg[i].from,eg[i].too,eg[i].val);
}
printf("%lld\n",dinic());
}
return 0;
}