Harry Potter and the Forbidden ForestTime Limit: 5000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 1802 Accepted Submission(s): 602 Problem Description Harry Potter notices some Death Eaters try to slip into Castle. The Death Eaters hide in the most depths of Forbidden Forest. Harry need stop them as soon as. The Forbidden Forest is mysterious. It consists of N nodes numbered from 0 to N-1. All of Death Eaters stay in the node numbered 0. The position of Castle is node n-1. The nodes connected by some roads. Harry need block some roads by magic and he want to minimize Input Input consists of several test cases. The first line is number of test case. Each test case, the first line contains two integers n, m, which means the number of nodes and edges of the graph. Each node is numbered 0 to n-1. Following m lines contains information about edges. Each line has four integers u, v, c, d. The first two integers mean two endpoints of the edges. The third one is cost of block the edge. The fourth one means directed (d = 0) or undirected (d = 1). Technical Specification 1. 2 <= n <= 1000 2. 0 <= m <= 100000 3. 0 <= u, v <= n-1 4. 0 < c <= 1000000 5. 0 <= d <= 1 Output For each test case: Output the case number and the answer of how many roads are blocked at least. Sample Input 3 4 5 0 1 3 0 0 2 1 0 1 2 1 1 1 3 1 1 2 3 3 1 6 7 0 1 1 0 0 2 1 0 0 3 1 0 1 4 1 0 2 4 1 0 3 5 1 0 4 5 2 0 3 6 0 1 1 0 0 1 2 0 1 1 1 1 1 2 1 0 1 2 1 0 2 1 1 1 Sample Output Case 1: 3 Case 2: 2 Case 3: 2 |
题意:有N个点(编号从0到N-1)和M条边,边的信息有四个——起点、终点、破坏该边需要的花费、d,其中当d为1时说明边是双向的,d为0时说明是单向边。问你在花费最小的前提下,阻断0和N-1需要破坏的最少边数。
分析:
1,在原图最小割不唯一的前提下,第一次求出的最小割的边数未必是最少的。在割边集的边权和相等的前提下,可能存在一个边数更少的最小割。
2,不管有多少个最小割,我们在原图跑一次最大流之后,残量网络里面满流的边一定是属于某个或多个最小割的,相应的没有满流的边一定不属于任何一个最小割。
3,这样问题就变成——在所有满流的边中破坏最少的边数来阻断0到N-1的路径,类似在最短路的边中破坏最少的边来阻断起点到终点的路径,只是多了对非最短路边(在本题中是非满流边)的处理。
思路:
1,先建图,在原图跑一次0到N-1的最大流。
2,以残量网络为基础构建新图。遍历所有正向弧,若满流则更改边权为1,否则边权为无穷大,注意对反向弧要初始化边的信息。
3,最后在新图求一次0到N-1的最小割,就是答案。
AC代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #define MAXN 1010 #define MAXM 400000+10 #define INF 0x3f3f3f3f using namespace std; struct Edge { int from, to, cap, flow, next; }; Edge edge[MAXM]; int head[MAXN], cur[MAXN], edgenum; int dist[MAXN]; bool vis[MAXN]; int N, M; void init() { edgenum = 0; memset(head, -1, sizeof(head)); } void addEdge(int u, int v, int w) { Edge E1 = {u, v, w, 0, head[u]}; edge[edgenum] = E1; head[u] = edgenum++; Edge E2 = {v, u, 0, 0, head[v]}; edge[edgenum] = E2; head[v] = edgenum++; } void getMap() { int a, b, c, d; while(M--) { scanf("%d%d%d%d", &a, &b, &c, &d); a++, b++; addEdge(a, b, c); if(d) addEdge(b, a, c); } } bool BFS(int s, int t) { queue<int> Q; memset(dist, -1, sizeof(dist)); memset(vis, false, sizeof(vis)); dist[s] = 0; vis[s] = true; Q.push(s); while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i = head[u]; i != -1; i = edge[i].next) { Edge E = edge[i]; if(!vis[E.to] && E.cap > E.flow) { dist[E.to] = dist[u] + 1; if(E.to == t) return true; vis[E.to] = true; Q.push(E.to); } } } return false; } int DFS(int x, int a, int t) { if(x == t || a == 0) return a; int flow = 0, f; for(int &i = cur[x]; i != -1; i = edge[i].next) { Edge &E = edge[i]; if(dist[E.to] == dist[x] + 1 && (f = DFS(E.to, min(a, E.cap - E.flow), t)) > 0) { edge[i].flow += f; edge[i^1].flow -= f; flow += f; a -= f; if(a == 0) break; } } return flow; } int Maxflow(int s, int t) { int flow = 0; while(BFS(s, t)) { memcpy(cur, head, sizeof(head)); flow += DFS(s, INF, t); } return flow; } int k = 1; void solve() { Maxflow(1, N); //对残量网络 进行处理 for(int i = 0; i < edgenum; i+=2) { Edge E = edge[i]; if(E.cap == E.flow)//满流的边 改变边权->1 { edge[i].cap = 1; edge[i].flow = 0; } else { edge[i].cap = INF; edge[i].flow = 0; } edge[i^1].cap = edge[i^1].flow = 0;//处理反向边 } printf("Case %d: %d\n", k++, Maxflow(1, N));//再求一次最小割就是答案 } int main() { int t; scanf("%d", &t); while(t--) { scanf("%d%d", &N, &M); init(); getMap(); solve(); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。