网址:https://vjudge.net/problem/HDU-6582
题意:
给出一个有向无环有重边图,删除一条边的代价就是边的长度,求使得点$1$和点$n$的最短路变长或者不存在最短路的最小代价。
题解:
对于一个图两点的最短路中构成的边构成的子图,如果在这个子图中两点不连通,则在实际的图中,最短路一定变长或甚至不存在最短路。故求一次点$1$到其他点的最短路,记录所有最短路上的边,建立子图,求子图上的最小割,即最大流。对于所有边,如果边的两个端点的最短路长度差的绝对值等于边权,则说明这条边在最短路上。
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e5+5;
const long long INF=0x3f3f3f3f3f3f3f3f;
const int inf=0x3f3f3f3f;
#define ll long long
struct Edge
{
int u,v;
long long w;
Edge(int a,int b,long long c)
{
u=a,v=b,w=c;
}
bool operator<(const Edge &a)const
{
return w>a.w;
}
};
vector<Edge>Eo[MAXN];
long long diss[MAXN];
bool vis[MAXN];
void dijkstra()
{
memset(diss,inf,sizeof(diss));
memset(vis,0,sizeof(vis));
priority_queue<Edge>que;
diss[1]=0;
que.push(Edge(1,1,0));
while(!que.empty())
{
auto tmp=que.top();
que.pop();
if(vis[tmp.v])
continue;
vis[tmp.v]=1;
for(auto &e:Eo[tmp.v])
{
if(diss[e.v]>diss[tmp.v]+e.w)
{
diss[e.v]=diss[tmp.v]+e.w;
if(!vis[e.v])
que.push(Edge(tmp.v,e.v,diss[e.v]));
}
}
}
}
//最大流模板
int sp,tp;//原点、汇点
struct node
{
int v,next;
ll cap;
}mp[MAXN*4];
int pre[MAXN],dis[MAXN],cur[MAXN];//cur为当前弧优化,dis存储分层图中每个点的层数(即到原点的最短距离),pre建邻接表
int cnt=0;
void init()//不要忘记初始化
{
cnt=0;
memset(pre,-1,sizeof(pre));
}
void add(int u,int v,int w)//加边
{
mp[cnt].v=v;
mp[cnt].cap=w;
mp[cnt].next=pre[u];
pre[u]=cnt++;
}
bool bfs()//建分层图
{
memset(dis,-1,sizeof(dis));
queue<int>q;
while(!q.empty())
q.pop();
q.push(sp);
dis[sp]=0;
int u,v;
while(!q.empty())
{
u=q.front();
q.pop();
for(int i=pre[u];i!=-1;i=mp[i].next)
{
v=mp[i].v;
if(dis[v]==-1&&mp[i].cap>0)
{
dis[v]=dis[u]+1;
q.push(v);
if(v==tp)
break;
}
}
}
return dis[tp]!=-1;
}
ll dfs(int u,ll cap)//寻找增广路
{
if(u==tp||cap==0)
return cap;
ll res=0,f;
for(int &i=cur[u];i!=-1;i=mp[i].next)
{
int v=mp[i].v;
if(dis[v]==dis[u]+1&&(f=dfs(v,min(cap-res,mp[i].cap)))>0)
{
mp[i].cap-=f;
mp[i^1].cap+=f;
res+=f;
if(res==cap)
return cap;
}
}
if(!res)
dis[u]=-1;
return res;
}
ll dinic(int n)
{
ll ans=0;
while(bfs())
{
for(int i=1;i<=n;i++)
cur[i]=pre[i];
ans+=dfs(sp,inf);
}
return ans;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
int n,m,a,b,c;
cin>>n>>m;
for(int i=1;i<=n;++i)
Eo[i].clear();
for(int i=0;i<m;++i)
{
cin>>a>>b>>c;
Eo[a].push_back(Edge(a,b,c));
}
dijkstra();
sp=1,tp=n;
init();
//cout<<endl;
for(int i=1;i<=n;++i)
for(auto &e:Eo[i])
if(diss[e.v]-diss[e.u]==e.w)
{
add(e.u,e.v,e.w);
add(e.v,e.u,0);
}
cout<<dinic(n)<<endl;
}
return 0;
}