zoukankan      html  css  js  c++  java
  • ZOJ4109 Welcome Party (并查集+优先队列)

    首先提取题目信息,我们需要计算朋友的关系,以及计算不开心值。

    其实看题目我们很容易就有并查集的感觉,之后我们要去验证这个算法是正确的

    题目要求的是求不开心值,那么我们就可以想到使用并查集求集合总数就可以了

    虽然朋友不存在传递性,但是这并不影响不开心值的大小,因为如果a和b是朋友,b和c是朋友

    那么虽然a和c不一定是朋友,但是假如a进去了,那么我们可以走b再走c,这样不会增加不开心值。

    因为我们有媒介,也就是并查集的传递性没有破坏。

    但是题目有个要求是说字典序最小,其实这也是常见的做法,我怀疑很有可能是出题人不想写spj所以才出了这个要求,这只需要使用优先队列就可以弹出符合条件的最小值了

    显然根据经验,我们可以用向前星或者是vector存储,这里写vector比较简单,毕竟不是正宗的图论题目

    我们发现,有几棵森林,就有多少个不开心值,所以不开心值就求出来了

    接下来我们需要设计一个0点,来存每个集合的头结点,这样比较方便,不然不好遍历所有的集合

    之后只需要常规操作,弹最小值遍历即可,每次遍历一个vector,把没出现过的存进来。

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<string> 
    #include<set>
    #include<map>
    #include<queue>
    using namespace std;
    typedef long long ll;
    const int N=1e6+10;
    int p[N];
    int st[N];
    int pos[N];
    int idx;
    vector<int> v[N];
    int find(int x){
        if(p[x]!=x)
        p[x]=find(p[x]);
        return p[x];
    }
    void bfs(int u){
        priority_queue<int,vector<int>,greater<int>> q;
        q.push(0);
        while(q.size()){
            int t=q.top();
            q.pop();
            if(!st[t]){
                st[t]=1;
                pos[idx++]=t;
                for(int i=0;i<v[t].size();i++){
                    if(!st[v[t][i]]){
                        q.push(v[t][i]);
                    }
                }
            }
        }
    }
    int main(){
        int t;
        int n,m;
        cin>>t;
        while(t--){
            cin>>n>>m;
            int i;
            idx=0;
            for(i=0;i<=n;i++){
                p[i]=i;
                v[i].clear();
                st[i]=0;
            }
            for(i=1;i<=m;i++){
                int a,b;
                scanf("%d%d",&a,&b);
                int pa=find(a),pb=find(b);
                if(pa>pb){
                    p[pa]=pb;
                }
                else{
                    p[pb]=pa;
                }
                v[a].push_back(b);
                v[b].push_back(a);
            }
            int ans=0;
            for(i=1;i<=n;i++){
                if(p[i]==i){
                    v[0].push_back(i);
                    ans++;
                }
            }
            bfs(0);
            printf("%d
    ",ans);
            for(i=1;i<idx-1;i++){
                printf("%d ",pos[i]);
            }    
            printf("%d
    ",pos[i]);
        }
    }
    View Code
  • 相关阅读:
    JAVA相关基础的知识吧
    Java测试调用.net 接口服务
    Java测试内存信息
    Java测试普通Java接口记录-TestHrmInterface
    那些年学不会的操作(写法/...)——记录一些靠搜索做过但总是记不住的东西
    正确的sybase批量插入语法
    新ZJJG项目相关接口开发记录-微信制证组成浅析
    bip项目的启用/调试+ 问题记录
    记录数组问题
    模糊匹配的查询条件/ 给下拉框加提示呢
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/12363962.html
Copyright © 2011-2022 走看看