2020牛客暑期多校训练营(第八场)

I题 Interesting Computer Game.

题意:
T组测试数据,每组输入一个n,然后输入n行,每行输入a b,可以选这两个数中没有选过的数,最多能选几个数。

思路:数据范围1e9,先离散化,起初每个数分别处于一个集合,输入a和b之后,如果a和b不相等,就合并a和b的集合,如果相等,就相当于自环,答案等于每个集合min(边数,点数) 之和。

并查集主要就是路径压缩和集合合并

#include <bits/stdc++.h>
#include <tr1/unordered_map>
#define ll long long
#define T int t;scanf("%d", &t);while(t--)
using namespace std;
using namespace std::tr1;
const int mod = 1e9 + 7;
const int maxn = 5e5 + 5;
unordered_map<int,int> mp;	//每个数的集合
pair<int,int> pp[maxn];		
int cnt[maxn];		//集合中点数量
int cnt_e[maxn];	//集合中边数量
int father[maxn];	//根节点
int num[maxn];		//数字
int find(int u){			//并查集路径压缩
	if(father[u] == u) return u;
	return father[u] = find(father[u]);
}
void bind(int u,int v){		//合并集合
	int x = find(u);
	int y = find(v);
	father[x] = y;
}
int main(){
	int cc = 1;
	T{
		int n;
		scanf("%d", &n);
		int cnt_n = 0;
		mp.clear();		//别忘记清零
		for(int i = 1; i <= n; i ++){
			int a,b;
			scanf("%d %d", &a, &b);
			pp[i] = make_pair(a,b);		//存输入的a b
			num[++cnt_n] = a;
			num[++cnt_n] = b;
		}
		sort(num+1,num+cnt_n+1);		//先排序,后去重
		cnt_n = (int)(unique(num+1,num+1+cnt_n)-(num + 1));	//离散化去重
		for(int i = 1; i <= cnt_n; i ++){		//初始化数组
			father[i] = i;		//每个点自己是自己的祖先
			cnt[i] = 1;			//每个集合只有一个点
			cnt_e[i] = 0;		//每个集合没有边
		}
		for(int i = 1; i <= cnt_n; i ++)
			mp[num[i]] = i;		//每个数处于不同集合

		for(int i = 1; i <= n; i ++){
			int u = mp[pp[i].first];	
			int v = mp[pp[i].second];		

			u = find(u);	
			v = find(v);

			int nu = cnt[u];
			int nv = cnt[v];

			int eu = cnt_e[u];
			int ev = cnt_e[v];

			bind(u,v);		//合并u和v的集合
			int k = find(u);	//找到合并之后的集合编号

			cnt[u] = 0;		//合并之后原集合点清零
			cnt[v] = 0;
			if(u != v) cnt[k] = nu + nv;	//如果集合不相同,新集合点数等于原集合点数之和
			else cnt[k] = nu;

			cnt_e[u] = 0;
			cnt_e[v] = 0;
			if(u != v) cnt_e[k] = eu + ev;	//如果集合不相同,新集合边数等于原集合边数之和
			else cnt_e[k] = eu;
			cnt_e[k] ++;	//不管怎么样,边数肯定要+1
		}
		ll ans = 0;
		for(int i = 1; i <= cnt_n; i ++)		//遍历每个集合
			ans += min(cnt[i],cnt_e[i]);
		printf("Case #%d: %lld\n",cc ++,ans);

	}

    return 0;
}

撒比题.
代码---------------------------->>>>>>

#include <bits/stdc++.h>  
#define ll long long
#define T int t;scanf("%d", &t);while(t--)
using namespace std;
const int mod = 1e9 + 7;
int check(string s1[],string s2[],string s3[]){
    for(int i = 0; i < 4; i ++){
        if(s1[i]=="*" || s2[i]=="*" || s3[i]=="*") continue;
        if(s1[i]!=s2[i] && (s1[i]==s3[i] || s2[i]==s3[i])) return 0;
        if(s1[i]!=s3[i] && (s1[i]==s2[i] || s2[i]==s3[i])) return 0;
        if(s2[i]!=s3[i] && (s1[i]==s3[i] || s1[i]==s2[i])) return 0;
    }
    return 1;
}
int main(){
    int cc = 1;
    T{
        string ss[1005][5];
        int n;
        scanf("%d", &n);
        string s;
        for(int i = 1; i <= n; i ++){
            cin>>s;
            int cnt = 0;
            for(int j = 0; j < s.length(); j ++){
                if(s[j]=='[') continue;
                if(s[j]==']'){
                    cnt++;
                    continue;
                }
                ss[i][cnt] += s[j];
            }
        }
        int f = 0;
        for(int i = 1; i <= n; i ++){
            for(int j = i + 1; j <= n ; j ++){
                for(int k = j + 1; k <= n; k ++){
                    if(check(ss[i], ss[j], ss[k])){
                        printf("Case #%d: %d %d %d\n",cc ++, i,j,k);
                        f = 1;
                        break;
                    }
                }
                if(f) break;
            }
            if(f) break;
        }
        if(f==0) printf("Case #%d: -1\n", cc ++);
    }
 
    return 0;
}

你可能感兴趣的:(并查集)