zoukankan      html  css  js  c++  java
  • POJ 3228 Gold Transportation(带权并查集,好题)

    参考链接:http://www.cnblogs.com/jiaohuang/archive/2010/11/13/1876418.html

    题意:地图上某些点有金子,有些点有房子,还有一些带权路径,问把所有金子运到房子里所要经过最小的最大相邻路是多少。

       也就是如果光用比“最小的最大相邻路”那条路更小的路是无法运完所有金子的,那么可以先对路径排序,然后一条一条取, 看看是否满足条件:即是否所有并查集的根节点的权值f[i]为非负。

    思路:首先想到的是,要能运完所有的金子,那么必须任意一个连通器中的储藏室的总容量V大于等于所含有的金子的总量C,也就是V-C>=0。那么就想到用一个数组存储该镇的状态,若是储藏室,则权值为储藏的                量;若为发现金子的地方,则权值为金子的量的负值。这样每次合并的时候,都要更新一下父节点,即父节点的权值要加上子节点的权值。最后根节点的权值即为该集合中V-C的值。

           若根节点的权值为非负,表明该点集中,可以储存宝藏的容量大于等于发现的宝藏,即这个点集能满足要求。

       若根节点的权值为负值,表明该点集中还有一定数量的宝藏需要储存,但是该集合已经没有房间能存储下了,即不能满足条件。

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    
    using namespace std;
    const int maxn=210;
    int n,m;
    int father[maxn],f[maxn]; //f[i]表示第i个镇所拥有的宝藏,如果为负值,表明此镇需要运出-f[i]的宝藏。如果为正值,表明可以储存f[i]的宝藏
    int ans;
    struct Edge {
        int u,v,w; //u、v是边的两端点,w是边的权值
        bool operator<(const Edge tmp) const{
            return w<tmp.w;
        }
    } edge[20010];
    
    void init(){
        for(int i=0;i<=n;i++){
            father[i]=i;
            f[i]=0;
        }
    }
    int find_root(int x) {
        if(father[x]!=x){
            father[x]=find_root(father[x]);
        }
        return father[x];
    }
    void Union(int x,int y){
        father[y]=x;
    }
    //判断是否所有集合都满足根节点的权值大于等于0
    bool ok(){
        int flag=1;
        for(int i=1;i<=n;i++){
            if(father[i]==i && f[i]<0){
                flag=0;
                break;
            }
        }
        if(flag)
            return true;
        else
            return false;
    }
    int main() {
        int store;
        while(scanf("%d",&n)!=EOF) {
            if(n==0)
                break;
            init();
            for(int i=1; i<=n; i++) {
                scanf("%d",&store);
                f[i]-=store;   //需要运出的宝藏
            }
            for(int i=1; i<=n; i++) {
                scanf("%d",&store);
                f[i]+=store;  //可以储存的宝藏,因为发现宝藏和储存宝藏的地方可能为同一个,所以这里累加就行
            }
            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+m+1);
            int u,v,i=1;
            //从最小的边开始取
            while(i<=m) {
                u=edge[i].u;
                v=edge[i].v;
                int x=find_root(u);
                int y=find_root(v);
                if(x!=y){
                    Union(x,y);
                    f[x]+=f[y];
                    if(ok()){
                        ans=i;
                        break;
                    }
                }
                i++;
            }
            if(i==m+1){
                printf("No Solution
    ");
            }
            else{
                printf("%d
    ",edge[ans].w);
            }
    
        }
    return 0;
    }
  • 相关阅读:
    文件操作类File
    文件流操作
    自动登录和解/加密
    redis---set类型常用命令
    div
    css2
    css-id选择器
    table标签
    段落标签-换行标签
    input-form-select-a-img-ul-dl标签
  • 原文地址:https://www.cnblogs.com/chenxiwenruo/p/3301900.html
Copyright © 2011-2022 走看看