Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 3077 | Accepted: 1100 |
Description
Input
Output
Sample Input
4 3 2 0 0 0 0 3 3 6 1 2 4 1 3 10 1 4 12 2 3 6 2 4 8 3 4 5 0
Sample Output
6
O(∩_∩)O~,又1A了。好难得
题意:有N个城市,每个城市都有一个金矿和一个仓库,已给出每个城市金矿的容量以及仓库的空间。
因为一个城市的仓库可能无法容纳该城市的所有金矿,所以需要通过运输方式把多余的金矿存储在其它城市的仓库里面。
现在给你M条无向的运输路线以及路线的长度。问你能不能使得所有金矿都能存储在仓库里面,若不能输出No Solution,否则求出运输过程中(可能不需要运输)所有被使用路线中的最大长度 的最小值。
很好想的思路吧:枚举运输过程中所有被使用路线中的最大长度,根据当前长度建边,跑一次最大流,看是否满流,若满流压缩长度,反之增大长度,然后继续查找。
建图:对当前枚举的mid值,设置超级源点source,超级汇点sink
1,source到所有城市建边,容量为城市的金矿数目;
2,所有城市到sink建边,容量为城市的仓库容量;
3,枚举所有路线,若路线长度小于或等于mid,则建边,容量为INF,因为只要我们愿意,我们可以无限转移两个城市的金矿。
若流入汇点的流量等于源点流出的流量,则说明所有金矿都已经放进仓库。
AC代码:
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> #define MAXN 210 #define MAXM 100000+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], cur[MAXN], edgenum, Redgenum; int dist[MAXN]; bool vis[MAXN]; int source, sink;//超级源点 超级汇点 int N, M; int sum;//记录总流量 void init() { edgenum = 0; memset(head, -1, sizeof(head)); } struct Node { int from, to, val; }; Node node[MAXM]; int nodenum; void addNode(int u, int v, int w) { Node E = {u, v, w}; node[nodenum++] = E; } int Max;//记录最大边权 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() { source = 0, sink = N+1; sum = 0; Max = 0; int a, b, c; for(int i = 1; i <= N; i++) { scanf("%d", &a); sum += a;//记录总流量 addEdge(source, i, a);//源点 到 城市i 建边 } for(int i = 1; i <= N; i++) { scanf("%d", &a); addEdge(i, sink, a); } scanf("%d", &M); nodenum = 0; while(M--) { scanf("%d%d%d", &a, &b, &c); addNode(a, b, c);//用邻接表建边 怕有重边 addNode(b, a, c); Max = max(Max, c);//更新最大边权 } } void addnew(int mid) { for(int i = 0; i < nodenum; i++) { Node E = node[i]; if(E.val <= mid) addEdge(E.from, E.to, INF);//建无穷大的边 } } 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; } void solve() { int left = 0, right = Max, mid;//最大边权作为区间右端点 int ans = INF; memcpy(Redge, edge, sizeof(edge)); memcpy(Rhead, head, sizeof(head)); Redgenum = edgenum; while(right >= left) { mid = (left + right) >> 1; memcpy(edge, Redge, sizeof(Redge)); memcpy(head, Rhead, sizeof(Rhead)); edgenum = Redgenum; addnew(mid); if(Maxflow(source, sink) == sum)//满流才满足条件 { ans = min(ans, mid); right = mid - 1; } else left = mid + 1; } if(ans == INF) printf("No Solution\n"); else printf("%d\n", ans); } int main() { while(scanf("%d", &N), N) { init(); getMap(); solve(); } return 0; }