There is a warTime Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 993 Accepted Submission(s): 283
Problem Description
There is a sea.
There are N islands in the sea. There are some directional bridges connecting these islands. There is a country called Country One located in Island 1. There is another country called Country Another located in Island N. There is a war against Country Another, which launched by Country One. There is a strategy which can help Country Another to defend this war by destroying the bridges for the purpose of making Island 1 and Island n disconnected. There are some different destroying costs of the bridges. There is a prophet in Country Another who is clever enough to find the minimum total destroying costs to achieve the strategy. There is an architecture in Country One who is capable enough to rebuild a bridge to make it unbeatable or build a new invincible directional bridge between any two countries from the subset of island 2 to island n-1. There is not enough time for Country One, so it can only build one new bridge, or rebuild one existing bridge before the Country Another starts destroying, or do nothing if happy. There is a problem: Country One wants to maximize the minimum total destroying costs Country Another needed to achieve the strategy by making the best choice. Then what’s the maximum possible result?
Input
There are multiple cases in this problem.
There is a line with an integer telling you the number of cases at the beginning. The are two numbers in the first line of every case, N(4<=N<=100) and M(0<=M<=n*(n-1)/2), indicating the number of islands and the number of bridges. There are M lines following, each one of which contains three integers a, b and c, with 1<=a, b<=N and 1<=c<=10000, meaning that there is a directional bridge from a to b with c being the destroying cost. There are no two lines containing the same a and b.
Output
There is one line with one integer for each test case, telling the maximun possible result.
Sample Input
Sample Output
|
题意:有N个岛屿和M条连接岛屿的有向边。已知在岛屿1上有一个城市A,在岛屿N上有一个城市B。现在城市A要攻打城市B,城市B为了保护自己,决定阻断城市A到自己的路径。
城市B里面有很聪明的人,他们总是可以用最小的代价来阻断A到B的路径。
城市A里面有很强的技工,他们可以在{2—N-1}里面任选两点a、b新建一条a到b的边或者重新改造原图M条边里面的一条边 使得新边无法被破坏。为了让城市B付出最大的代价,他们一定会选择最优的建边方案。
问你:城市B需要付出的最大代价。
分析:最小割一定会把原图分成两个点集。一个是源点能到达的S集,一个是能到达汇点的T集(可达是针对残量网络而言)。设点a属于S集,点b属于T集,那么最优的建边方案一定是建a -> b的边。
实现过程
1,求出原图的最小割ans,;
2,在残量网络里求出S集和T集;
3,枚举两集合里面的点,在残量网络里面建一条新边求最小割。得到最大的最小割need;
4,最后结果就是ans+need。
AC代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #define MAXN 110 #define MAXM 20000+10 #define INF 0x3f3f3f3f using namespace std; struct Edge { int from, to, cap, flow, next; }; Edge edge[MAXM], Redge[MAXM]; int head[MAXN], Rhead[MAXN], edgenum, Redgenum, cur[MAXN]; 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++; } 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 Sr[MAXN], Tr[MAXN];//记录S集 T集里面的点 int S, T; void find_S(int u) { for(int i = head[u]; i != -1; i = edge[i].next) { Edge E = edge[i]; if(vis[E.to]) continue; if(E.cap > E.flow) { vis[E.to] = true; Sr[S++] = E.to; find_S(E.to); } } } void solve() { init(); int a, b, c; for(int i = 0; i < M; i++) { scanf("%d%d%d", &a, &b, &c); addEdge(a, b, c); } int ans = Maxflow(1, N);//最小割 memset(vis, false, sizeof(vis)); S = 0; vis[1] = true;//1不能再访问 find_S(1); T = 0; for(int i = 2; i <= N-1; i++) if(!vis[i]) Tr[T++] = i;//记录T集里面的点 memcpy(Rhead, head, sizeof(head)); memcpy(Redge, edge, sizeof(edge)); Redgenum = edgenum; int need = 0;//额外代价 for(int i = 0; i < S; i++) { for(int j = 0; j < T; j++) { memcpy(head, Rhead, sizeof(Rhead)); memcpy(edge, Redge, sizeof(Redge)); edgenum = Redgenum; addEdge(Sr[i], Tr[j], INF);//建新边 need = max(need, Maxflow(1, N)); } } printf("%d\n", ans+need); } int main() { int t; scanf("%d", &t); while(t--) { scanf("%d%d", &N, &M); solve(); } return 0; }