1. 程式人生 > 實用技巧 >《2019 Multi-University Training Contest 1》 補

《2019 Multi-University Training Contest 1》 補

Path:

題意:用最少的代價,刪除一些邊,使得最短路變長。

思路:

https://blog.csdn.net/jerry99s/article/details/96907292(大佬講得非常好)

我們將所有最短路上的邊,建立一張新的圖。

以1為源點,n為匯點。求最小割。

這時的最小割即為最小花費(這很顯然。)

首先,如何求該條邊是最短路上的邊。

在牛客某次比賽時做到過思路。

對於邊(x,y,z),dis表示最短路

dis[1-x] + z +dis[x-n]。即滿足該邊是最短路上的邊,(這也很顯然)。

那麼,先原圖跑出1到所有點的最短路。

然後再建反圖,跑出n到所以點的最短路。

最後列舉邊去建圖,然後跑最大流即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double ld;
typedef pair<LL,int> pii;
const int N = 1e4+5;
const int M = 5e4+5;
const LL Mod = 1e9+7;
#define rg register
#define pi acos(-1)
#define INF 1e18
#define INM INT_MIN
#define dbg(ax) cout << "now this num is " << ax << endl;
inline 
int read() { int x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } int n,m,s,t,cnt = -1; int head[N],dep[N],cur[N]; LL dis1[N],dis2[N];
struct Node{int to;LL dis;int next,st;}e[M<<1],edge[M<<1]; vector<Node> G[N],RG[N]; inline void add(int u,int v,int w) { e[++cnt].to = v,e[cnt].dis = w,e[cnt].next = head[u],head[u] = cnt; e[++cnt].to = u,e[cnt].dis = 0,e[cnt].next = head[v],head[v] = cnt; } bool bfs()//分層 { queue<int> Q; memset(dep,-1,sizeof(dep)); dep[s] = 0; Q.push(s); while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i=head[u];i!=-1;i=e[i].next) { int y = e[i].to,d = e[i].dis; if(dep[y] == -1 && d > 0) { dep[y] = dep[u]+1; Q.push(y); } } } return dep[t] != -1; } int dfs(int u,int flow) { int nowflow = 0,k; if(u == t) return flow; for(int i=head[u];i!=-1;i=e[i].next) { cur[u] = i;//當前弧優化 int y = e[i].to,d = e[i].dis; if((dep[y] == dep[u]+1) && d > 0) { if(k = dfs(y,min(flow-nowflow,d))) { e[i].dis -= k; e[i^1].dis += k; nowflow += k; if(nowflow == flow) break; } } } if(nowflow == 0) dep[u] = -1;//炸點優化 return nowflow; } LL slove() { LL ans = 0; while(bfs()) { for(int i=1;i<=n;++i) cur[i] = head[i]; ans += dfs(s,INF); } return ans; } void dij(int s,LL *dis,vector<Node> vec[]) { for(int i = 1;i <= n;++i) dis[i] = INF; dis[s] = 0; priority_queue<pii,vector<pii>,greater<pii> > Q; Q.push(pii{dis[s],s}); while(!Q.empty()) { int u = Q.top().second; LL d = Q.top().first; Q.pop(); if(d > dis[u]) continue; for(auto v : vec[u]) { if(dis[v.to] > dis[u]+v.dis) { dis[v.to] = dis[u]+v.dis; Q.push(pii{dis[v.to],v.to}); } } } } int main() { int ca;ca = read(); while(ca--) { n = read(),m = read(); memset(head,-1,sizeof(head)); cnt = -1; for(int i = 1;i <= n;++i) G[i].clear(),RG[i].clear(); for(int i = 1;i <= m;++i) { int x,y,z; x = read(),y = read(),z = read(); edge[i].st = x,edge[i].to = y,edge[i].dis = z; G[x].push_back(Node{y,z}); RG[y].push_back(Node{x,z}); } dij(1,dis1,G); dij(n,dis2,RG); for(int i = 1;i <= m;++i) { int x = edge[i].st,y = edge[i].to,z = edge[i].dis; if(dis1[x]+dis2[y]+z == dis1[n]) add(x,y,z); } s = 1,t = n; LL ans = slove(); printf("%lld\n",ans); } system("pause"); return 0; }
View Code