POJ - 3228 Gold Transportation(二分+最大流 或 最小生成树)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/GYH0730/article/details/82845144

Gold Transportation

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 3661   Accepted: 1305

Description

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

Source

South Central China 2007 hosted by NUDT

这道题很容易构建出最大流模型,建立源点与汇点,源点向其它各点连接一条边,流量为该点的金矿量,其它各点向汇点连接一条边,流量为该点能存储的金矿量,题目给出的m条双向边的边权为INF,求经过边的最大值的最小值,二分就行了,判断是否满流

#include <stdio.h>
#include <algorithm>
#include <queue>
#include <string.h>
#include <vector>
using namespace std;
const int MAXN = 205;
const int MAXM = 100005;
const int INF = 0x3f3f3f3f;
struct Edge1
{
	int from,to,cap,flow;
};
struct Dinic
{
	int n,m,s,t;
	vector<Edge1> edges;
	vector<int> G[MAXN];
	bool vis[MAXN];
	int d[MAXN];
	int cur[MAXN];
	void init(int n)
	{
		this -> n = n;
		for(int i = 0; i <= n + 1; i++){
			G[i].clear();
		}
		edges.clear();
	}
	void AddEdge(int from,int to,int cap)
	{
		edges.push_back((Edge1){from,to,cap,0});
		edges.push_back((Edge1){to,from,0,0});
		m = edges.size();
		G[from].push_back(m - 2);
		G[to].push_back(m - 1);
	}
	bool BFS()
	{
		memset(vis,0,sizeof(vis));
		queue<int> Q;
		Q.push(s);
		d[s] = 0;
		vis[s] = 1;
		while(!Q.empty()) {
			int x = Q.front();
			Q.pop();
			for(int i = 0; i < G[x].size(); i++) {
				Edge1& e = edges[G[x][i]];
				if(!vis[e.to] && e.cap > e.flow) {
					vis[e.to] = 1;
					d[e.to] = d[x] + 1;
					Q.push(e.to);
				}
			}
		}
		return vis[t];
	}
	int DFS(int x,int a)
	{
		if(x == t || a == 0) return a;
		int flow = 0,f;
		for(int& i = cur[x]; i < G[x].size(); i++) {
			Edge1& e = edges[G[x][i]];
			if(d[x] + 1 == d[e.to] && (f = DFS(e.to,min(a,e.cap - e.flow))) > 0) {
				e.flow += f;
				edges[G[x][i] ^ 1].flow -= f;
				flow += f;
				a -= f;
				if(a == 0) break;
			}
		}
		return flow;
	}
	int Maxflow(int s,int t) {
		this -> s = s,this -> t = t;
		int flow = 0;
		while(BFS()) {
			memset(cur,0,sizeof(cur));
			flow += DFS(s,INF);
		}
		return flow;
	}
}din;
int gold[MAXN],store[MAXN];
int n,mp[MAXN][MAXN],m,d[MAXM];
int sum;
bool judge(int mid)
{
    int S = 0,T = n + 1;
    din.init(n + 2);
    for(int i = 1; i <= n; i++) {
        din.AddEdge(S,i,gold[i]);
        din.AddEdge(i,T,store[i]);
    }
    for(int i = 1; i <= n; i++) {
        for(int j = i + 1; j <= n; j++) {
            if(mp[i][j] && mp[i][j] <= mid) {
                din.AddEdge(i,j,INF);
                din.AddEdge(j,i,INF);
            }
        }
    }
    return din.Maxflow(S,T) == sum ;
}
int main(void)
{
    int u,v,w;
    while(scanf("%d",&n) != EOF && n) {
        sum = 0;
        memset(mp,0,sizeof(mp));
        for(int i = 1; i <= n; i++) {
            scanf("%d",&gold[i]);
            sum += gold[i];
        }
        for(int i = 1; i <= n; i++) {
            scanf("%d",&store[i]);
        }
        scanf("%d",&m);
        for(int i = 1; i <= m; i++) {
            scanf("%d %d %d",&u,&v,&w);
            mp[u][v] = mp[v][u] = w;
            d[i] = w;
        }
        sort(d + 1,d + 1 + m);
        int L,R,mid;
        L = 1;R = m;
        int ans = INF;
        while(L <= R) {
            mid = (L + R) / 2;
            if(judge(d[mid])) {
                R = mid - 1;
                ans = min(d[mid],ans);
            }
            else {
                L = mid + 1;
            }
        }
        if(ans == INF) printf("No Solution\n");
        else printf("%d\n",ans);
    }
    return 0;
}

另一种做法则利用到了求最小生成树的kruskal思想

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int MAXN = 205;
const int MAXM = 10005;
struct Edge
{
    int u,v,w;
}edge[MAXM];
int pre[MAXN],gold[MAXN],store[MAXN];
int Find(int x)
{
    if(x == pre[x]) return x;
    else return pre[x] = Find(pre[x]);
}
bool cmp(struct Edge a,struct Edge b)
{
    return a.w < b.w;
}
int n;
bool check()
{
    for(int i = 1; i <= n; i++) {
        int u = Find(i);
        if(gold[u] > store[u]) return false;
    }
    return true;
}
int main(void)
{
    int m,u,v,w,fu,fv;
    int sum1,sum2;
    while(scanf("%d",&n) != EOF && n) {
        sum1 = 0;
        sum2 = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d",&gold[i]);
            sum1 += gold[i];
            pre[i] = i;
        }
        for(int i = 1; i <= n; i++) {
            scanf("%d",&store[i]);
            sum2 += store[i];
        }
        scanf("%d",&m);
        for(int i = 1; i <= m; i++) {
            scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].w);
        }
        sort(edge + 1,edge + 1 + m,cmp);
        if(sum1 > sum2) {
            printf("No Solution\n");
            continue;
        }
        if(check()) {
            printf("0\n");
            continue;
        }
        int ans = -1;
        for(int i = 1; i <= m; i++) {
            u = edge[i].u;
            v = edge[i].v;
            fu = Find(u);
            fv = Find(v);
            if(fu == fv) continue;
            pre[fv] = fu;
            gold[fu] += gold[fv];
            gold[fv] = 0;
            store[fu] += store[fv];
            store[fv] = 0;
            if(check()) {
                ans = edge[i].w;
                break;
            }
        }
        if(ans == -1) printf("No Solution\n");
        else printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/GYH0730/article/details/82845144