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\n",ans);
        for(i=1;i<idx-1;i++){
            printf("%d ",pos[i]);
        }
        printf("%d\n",pos[i]);
    }
}

原文地址:https://www.cnblogs.com/ctyakwf/p/12363962.html

时间: 2024-10-12 10:17:10

ZOJ4109 Welcome Party (并查集+优先队列)的相关文章

“玲珑杯”ACM比赛 Round #7 B -- Capture(并查集+优先队列)

题意:初始时有个首都1,有n个操作 +V表示有一个新的城市连接到了V号城市 -V表示V号城市断开了连接,同时V的子城市也会断开连接 每次输出在每次操作后到首都1距离最远的城市编号,多个距离相同输出编号最小的城市 输入数据保证正确,每次添加与删除的城市一定是与首都相连的 题解:每次都只需要知道最远且编号最小的城市,所以直接使用优先队列存储 如果是+V就使用并查集(不能路径压缩)添加上然后加入优先队列,接着直接弹出首元素就是结果 如果是-V则把V指向0,接着弹出优先队列的第一个元素 如果他与1相连就

POJ 1456 贪心 并查集

看一下中文版的题目就好,英文题目太晦涩了. 有两种方法可以解题 一种是贪心+优先队列 另一种是贪心+并查集 优先队列  需要说的都在代码注释里 #include<cstdio> #include<queue> #include<algorithm> using namespace std; struct s{ int day, val; }arr[100005]; bool cmp(s a, s b){ if(a.day != b.day) return a.day &

[POJ1456]Supermarket(贪心 + 优先队列 || 并查集)

传送门 1.贪心 + 优先队列 按照时间排序从前往后 很简单不多说 ——代码 1 #include <queue> 2 #include <cstdio> 3 #include <iostream> 4 #include <algorithm> 5 #define N 10001 6 7 int n, t, ans; 8 std::priority_queue <int, std::vector <int>, std::greater &l

优先队列 + 并查集 + 字典树 + 树状数组 + 线段树 + 线段树点更新 + KMP +AC自动机 + 扫描线

这里给出基本思想和实现代码 . 优先队列 : 曾经做过的一道例题       坦克大战 1 struct node 2 { 3 int x,y,step; 4 friend bool operator <(node s1,node s2) // 定义结构体 的时候 这个 就是 用于 优先队列的 基准排序 5 { 6 return s1.step>s2.step; // 步数小的 在上 为小顶堆 7 } 8 }; 9 priority_queue<node>Q; // 优先队列的结构

ZOJ - 4109 - Welcome Party (并查集 + BFS + 优先队列)

题目地址 题目大意:n个人,m种关系 (a和b是朋友),可以看作 n个点,m条边, 用图论的知识解题 问在使最少人不开心的情况下,输出进房间字典序排序最小的顺序.(如果在小A进房间之前房间内没有他的朋友,他就不开心) 使用并查集分块,每个并查集的根节点和独立点(无朋友)的总个数就是输出的不开心的人数.     使用BFS和优先队列遍历存入的图,保证字典序最小.将路径存入答案数组. 代码: #include <bits/stdc++.h> using namespace std; const i

C - Justice(优先队列+并查集)

Put simply, the Justice card represents justice, fairness, truth and the law. You are being called to account for your actions and will be judged accordingly. If you have acted in a way that is in alignment with your Higher Self and for the greater g

In Touch (hdu 5361 优先队列的Dij + 并查集优化)

In Touch Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 1109    Accepted Submission(s): 298 Problem Description There are n soda living in a straight line. soda are numbered by 1,2,-,n from

POJ 2263 Heavy Cargo(二分+并查集)

题目地址:POJ 2263 这题是在网上的一篇关于优先队列的博文中看到的..但是实在没看出跟优先队列有什么关系..我用的二分+并查集做出来了... 二分路的载重量.然后用并查集检查是否连通. 代码如下: #include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <ctype.h> #

算法导论——最小生成树:Kruskal算法(利用了并查集)

package org.loda.graph; import org.loda.structure.MinQ; import org.loda.structure.Queue; import org.loda.util.In; /** * * @ClassName: KruskalMST * @Description:Kruskal最小生成树算法 * @author minjun * @date 2015年5月25日 下午10:50:01 * */ public class KruskalMST