codeforces1702E(考虑奇偶性,并查集,dfs)

Problem - E - Codeforces

解题思路:

首先这道题不能用贪心,然后是每个数不能超过三次,一个骨牌的两面数字不能相同,满足这些条件后,如果把骨牌的数字按边连接起来,就会发现会形成环,因为形成的边度数都是2,形成环之后,选骨牌的行为就变成了选不相邻的边,若是奇数,则选的边必有相邻的,故问题就转换成了数环的边数,可以用dfs数,也可以用并查集数,dfs的话将图存起来数就行,用并查集的话,就算每个连通块的元素数;

代码:

并查集

#include<bits/stdc++.h>
#define all(x) x.begin(),x.end()
#define int long long 
#define maxn 200005
#define endl "\n"
using namespace std;
vector<int>b(maxn),sze(maxn);
int find(int x){
	while(x!=b[x])
	x=b[x]=b[b[x]];
	return x;
}
void merge(int x,int y){
	x=find(x);
	y=find(y);
	if(x!=y){
		sze[min(x,y)]+=sze[max(x,y)]; 
		b[max(x,y)]=b[min(x,y)];
	}
}
void solve(){
	int n;
	cin>>n;
	fill(all(sze),1);
	for(int i=1;i<=n;i++){
		b[i]=i;
	}
	int flag=0;
	vector<int>d(n+1);
	for(int i=1;i<=n;i++){
		int u,v;
		cin>>u>>v;
		merge(u,v);
		d[u]++;
		d[v]++;
		if(d[u]>2||d[v]>2){
			flag=1;
		}
	}
	if(flag==1){
		cout<<"NO"<<endl;
		return;
	}
	for(int i=1;i<=n;i++){
		if(b[i]==i){
			if(sze[i]%2==1){
				cout<<"NO"<<endl;
				return ;
			}
		}
	}
	cout<<"YES"<<endl;
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int test=1;
	cin>>test;
    while(test--){
        solve();
    }
    return 0;
}

dfs

#include<bits/stdc++.h>
#define all(x) x.begin(),x.end()
#define int long long 
#define maxn 200005
using namespace std;
void dfs(vector<vector<int>>&a,vector<int>&c,int &dep,int x,int y){
	int t=0;
	int ans=0;
	c[x]=1;
	dep+=1;
	for(auto i:a[x]){
		if(i==y)continue;
		if(c[i]==0)
		dfs(a,c,dep,i,x);
	}
}
void solve(){
	int n;
	cin>>n;
	vector<vector<int>>a(n+1);
	vector<int>b(n+1);
	int flag=0;
	for(int i=1;i<=n;i++){
		int u,v;
		cin>>u>>v;
		b[u]++;
		b[v]++;
		if(b[u]>2||b[v]>2){
			flag=1;
		}
		a[u].push_back(v);
		a[v].push_back(u);
	}
	if(flag==1){
		cout<<"NO"<<endl;
		return;
	}
	int dep;
	vector<int>c(n+1);
	for(int i=1;i<=n;i++){
		dep=0;
		if(c[i]==0){
			dfs(a,c,dep,i,0);
		}
		if(dep%2==1){
			cout<<"NO"<<endl;
			return;
		}
	}
	cout<<"YES"<<endl;
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int test=1;
	cin>>test;
    while(test--){
        solve();
    }
    return 0;
}

总结:

对于贪心:

先交一发贪心,如果错了就说明不能用贪心,再想其他办法

对于奇偶:

很多题可以从奇偶的特性出发分析问题

对于环:

以后看到pair类型的输入,不经可以考虑坐标,还可以考虑组成图

关于并查集:

以后那种输入边判断连通性的题可以用并查集,并查集尽量让小的数做祖宗,当下标和数组内容相同时,那么这个数就是根

posted @ 2025-04-29 17:38  C微  阅读(4)  评论(0)    收藏  举报