poj 3228 Gold Transportation 【二分 + 最大流 判断是否满流】

Gold Transportation
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 3077   Accepted: 1100

Description

poj 3228 Gold Transportation 【二分 + 最大流 判断是否满流】_第1张图片Recently, a number of gold mines have been discovered in Zorroming State. To protect this treasure, we must transport this gold to the storehouses as quickly as possible. Suppose that the Zorroming State consists of N towns and there are M bidirectional roads among these towns. The gold mines are only discovered in parts of the towns, while the storehouses are also owned by parts of the towns. The storage of the gold mine and storehouse for each town is finite. The truck drivers in the Zorroming State are famous for their bad temper that they would not like to drive all the time and they need a bar and an inn available in the trip for a good rest. Therefore, your task is to minimize the maximum adjacent distance among all the possible transport routes on the condition that all the gold is safely transported to the storehouses.

Input

The input contains several test cases. For each case, the first line is integer N(1<=N<=200). The second line is N integers associated with the storage of the gold mine in every towns .The third line is also N integers associated with the storage of the storehouses in every towns .Next is integer M(0<=M<=(n-1)*n/2).Then M lines follow. Each line is three integers x y and d(1<=x,y<=N,0<d<=10000), means that there is a road between x and y for distance of d. N=0 means end of the input.

Output

For each case, output the minimum of the maximum adjacent distance on the condition that all the gold has been transported to the storehouses or "No Solution".

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;
}




你可能感兴趣的:(poj 3228 Gold Transportation 【二分 + 最大流 判断是否满流】)