hdu 5438 并查集

题目:hdu 5438
题意:
有一些池塘用管道连接着,但是主人没钱了,要清除一些与其他池塘相连数目少于2的池塘,包括一些独立的池塘。每个池塘都有一个价值,最后在删完一些池塘后求出有奇数个连通块的池塘的价值和。
分析:
记得是一道网络赛的题目。而且还记得我做的时候,用了deque,总是超时。又做了一下,好简单的题目。就是模拟一下删池塘的操作就好。先用并查集记录一下每个池塘所处的连通块,然后开始把不符合要求的池塘删去,最后把同一个连通块中并且度数大于1的池塘找出来,如果是奇数个,求一下和就好了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
typedef long long ll;
const int N=10000+5;
int fa[N],in[N],val[N];
vector<int>g[N];
int findfa(int x){return x==fa[x]?x:fa[x]=findfa(fa[x]);}
int main()
{
    int T; scanf("%d",&T);
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=n;i++)scanf("%d",&val[i]),g[i].clear(),fa[i]=i;
        memset(in,0,sizeof(in));
        int u,v;
        for(int i=0;i<m;i++){
            scanf("%d%d",&u,&v);
            g[u].push_back(v); g[v].push_back(u);
            in[u]++; in[v]++;
            int x=findfa(u),y=findfa(v);
            fa[x]=y;
        }
        while(1){
            bool flag=0;
            for(int i=1;i<=n;i++){
                if(in[i]==1){
                    in[i]=0;
                    for(int j=0;j<g[i].size();j++)in[g[i][j]]--;
                    flag=1;
                }
            }
            if(!flag)break;
        }
        ll ans=0;
        vector<int>vec[n+1];
        for(int i=1;i<=n;i++){
            int x=findfa(i);
            if(in[i]>1)vec[x].push_back(i);
        }
        for(int i=1;i<=n;i++){
            if(vec[i].size()&1){
                for(int j=0;j<vec[i].size();j++)ans+=val[vec[i][j]];
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/01world/p/5651248.html