HDU6582 Path 最短路+最小割
网址: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; }