標籤:hdu 多校2015 最大流 最短路 最小割
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=5294
Problem DescriptionInnocent Wu follows Dumb Zhang into a ancient tomb. Innocent Wu’s at the entrance of the tomb while Dumb Zhang’s at the end of it. The tomb is made up of many chambers, the total number is N. And there are M channels connecting the chambers. Innocent Wu wants to catch up Dumb Zhang to find out the answers of some questions, however, it’s Dumb Zhang’s intention to keep Innocent Wu in the dark, to do which he has to stop Innocent Wu from getting him. Only via the original shortest ways from the entrance to the end of the tomb costs the minimum time, and that’s the only chance Innocent Wu can catch Dumb Zhang.
Unfortunately, Dumb Zhang masters the art of becoming invisible(奇門遁甲) and tricks devices of this tomb, he can cut off the connections between chambers by using them. Dumb Zhang wanders how many channels at least he has to cut to stop Innocent Wu. And Innocent Wu wants to know after how many channels at most Dumb Zhang cut off Innocent Wu still has the chance to catch Dumb Zhang.
InputThere are multiple test cases. Please process till EOF.
For each case,the first line must includes two integers, N(<=2000), M(<=60000). N is the total number of the chambers, M is the total number of the channels.
In the following M lines, every line must includes three numbers, and use ai、bi、li as channel i connecting chamber ai and bi(1<=ai,bi<=n), it costs li(0<li<=100) minute to pass channel i.
The entrance of the tomb is at the chamber one, the end of tomb is at the chamber N.
OutputOutput two numbers to stand for the answers of Dumb Zhang and Innocent Wu’s questions.
Sample Input
8 91 2 22 3 22 4 13 5 34 5 45 8 11 6 26 7 57 8 1
Sample Output
2 6
AuthorFZUACM
Source2015 Multi-University Training Contest 1
轉
題意:
給出n個墓室,m條路徑,一個人在1號墓室(起點),另一個人在n號墓室(終點);
起點的那個人只有通過最短路徑才能追上終點的那個人,而終點的那個人能切斷任意路徑。
第一問——終點那人要使起點那人不能追上的情況下可以切的最少的路徑數,輸出最少的路徑數
第二問——起點那人能追上終點那人的情況下,終點那人能切斷的最多的路徑數,輸出最多的路徑數
PS:
先跑最短路。
然後通過 dist[i]-dist[j] == map[j][i]
如果符合的話 map[j][i]就是 最短路中的一條邊。
然後把這些最短路的邊 建圖,跑最大流,流量是有多少邊權相同的重邊,跑出來就是最小割,也就是阻斷所有最短路的最小花費。花費是每破壞一條路為1。所以出來的值,就是破壞了多少的邊。
然後如最大流同樣的建邊,跑最短路,邊權為1,跑出來的最短路dist[n],就是 跨越邊數最少的 最短路的邊數了。
官方題解:
代碼如下:
#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <iostream>#include <algorithm>using namespace std;#define INF 0x3f3f3f3f#define MAXN 800047//點數的最大值#define MAXM 2247//邊數的最大值int head[MAXM], pre[MAXM];int dep[MAXM], cur[MAXM], gap[MAXM];//gap[x]=y :說明殘留網路中dep[i]==x的個數為yint EN;struct Edge{ int to,next,cap,flow;} edge[MAXN]; //注意是MAXMint tol;int k, c, m;int s, e;//源點,匯點int map[MAXM][MAXM];int cost1[MAXM][MAXM], cost2[MAXM][MAXM];int num[MAXM][MAXM];//記錄邊數,>1 既有重邊//加邊,單向圖三個參數,雙向圖四個參數void addedge(int u,int v,int w,int rw = 0){ edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++;}int Q[MAXN];void BFS(int start,int end){ memset(dep,-1,sizeof(dep)); memset(gap,0,sizeof(gap)); gap[0] = 1; int front = 0, rear = 0; dep[end] = 0; Q[rear++] = end; while(front != rear) { int u = Q[front++]; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(dep[v] != -1)continue; Q[rear++] = v; dep[v] = dep[u] + 1; gap[dep[v]]++; } }}int S[MAXN];//輸入參數:起點、終點、點的總數//點的編號沒有影響,只要輸入焦點的總數int sap(int start,int end,int N){ BFS(start,end); memcpy(cur,head,sizeof(head)); int top = 0; int u = start; int ans = 0; while(dep[start] < N) { if(u == end) { int Min = INF; int inser; for(int i = 0; i < top; i++) if(Min > edge[S[i]].cap - edge[S[i]].flow) { Min = edge[S[i]].cap - edge[S[i]].flow; inser = i; } for(int i = 0; i < top; i++) { edge[S[i]].flow += Min; edge[S[i]^1].flow -= Min; } ans += Min; top = inser; u = edge[S[top]^1].to; continue; } bool flag = false; int v; for(int i = cur[u]; i != -1; i = edge[i].next) { v = edge[i].to; if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u]) { flag = true; cur[u] = i; break; } } if(flag) { S[top++] = cur[u]; u = v; continue; } int Min = N; for(int i = head[u]; i != -1; i = edge[i].next) if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) { Min = dep[edge[i].to]; cur[u] = i; } gap[dep[u]]--; if(!gap[dep[u]])return ans; dep[u] = Min + 1; gap[dep[u]]++; if(u != start)u = edge[S[--top]^1].to; } return ans;}void Dijkstra(int s, int n, int cost[][MAXM], int dis[MAXM]){ //int dis[MAXM];//記錄到任意點的最短距離 int mark[MAXM];//記錄被選中的結點 int i, j, k; for(i = 1; i <= n; i++) { mark[i] = 0;//初始化所有結點,每個結點都沒有被選中 dis[i] = INF; } mark[s] = 1;//start結點被選中 dis[s] = 0;//將start結點的的距離設定為0 int MIN;//設定最短的距離。 for(i = 1; i <= n; i++) { k = 1;//賦初值很重要 MIN = INF; for(j = 1; j <= n; j++) { if(!mark[j] && dis[j] < MIN)//未被選中的結點中,距離最短的被選中 { MIN = dis[j] ; k = j; } } mark[k] = 1;//標記為被選中 for(j = 1; j <= n; j++) { if(!mark[j] && dis[j]>dis[k] + cost[k][j])//修改剩餘結點的最短距離 { dis[j] = dis[k] + cost[k][j]; } } }}void init(){ memset(head,-1,sizeof(head)); memset(cost1,INF,sizeof(cost1)); memset(cost2,INF,sizeof(cost2)); memset(num,0,sizeof(num)); EN = 0;}int main(){ int n, m; int u, v, w; int dis1[MAXM], dis2[MAXM]; while(~scanf("%d%d",&n,&m)) { init(); for(int i = 1; i <= n; i++) { cost1[i][i] = 0; } for(int i = 1; i <= m; i++) { scanf("%d%d%d",&u,&v,&w); if(cost1[u][v] > w) { cost1[u][v] = w; cost1[v][u] = w; num[u][v] = 1; num[v][u] = 1; } else if(cost1[u][v] == w)//重邊 { num[u][v]++; num[v][u]++; } } Dijkstra(1,n,cost1,dis1); for(int i = 1; i <= n; i++) { cost2[i][i] = 0; } for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if(i != j) { if(dis1[i] - dis1[j] == cost1[i][j])//最短路的邊 { cost2[j][i] = 1; addedge(j,i,num[i][j]); } } } } Dijkstra(1,n,cost2,dis2); printf("%d %d\n",sap(1,n,n),m-dis2[n]); } return 0;}
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
HDU 5294 Tricks Device(多校2015 最大流+最短路啊)