题目链接:https://codeforc.es/contest/1702/problem/E
第一次cf周赛做到了图论的题,真的挺开心的。
这道题题的大意就是,给出一个数n,然后给出n对数a,b。让我们构造两组数,这两组数的元素都是1-n,且没有重复元素。
solution:利用并查集判重,当一个元素被奇数个数视为路径时,构造不出来,否则可以构造出来。另外一个条件就是每个数出现次数为2次。
这个题我在做的时候,只想着去构造一个可行路径,因为这个题具有对称性质,但是我忽略掉的地方就是可行路径的查找不能只顺序遍历一次。
这个题还有一个做法就是用dfs去跑二分图染色。看到这个题解的时候,我恍然大悟啊,这不就是一个二分图的问题嘛。
并查集code:
#include<bits/stdc++.h> using namespace std; const int nn = 2*1e5+10; int zufu[nn]; int cnt[nn]; int numcnt[nn]; int root(int a) { int x = a,c; while(x!=zufu[x]) x = zufu[x]; while(zufu[a]!=x) { c = zufu[a]; zufu[a] = x; a = c; } return x; } int main() { int t; cin>>t; while(t--){ int n,x,y; scanf("%d",&n); for(int i=1;i<=n;i++) zufu[i] = i,cnt[i]=numcnt[i]=0; for(int i=1;i<=n;i++) { scanf("%d%d",&x,&y); numcnt[x]++;numcnt[y]++; x=root(x);y=root(y); zufu[x] = y; } for(int i=1;i<=n;i++){ cnt[root(i)]++; } int flag = 1; for(int i=1;i<=n;i++) if(cnt[i]&1||numcnt[i]!=2) flag = 0; if(flag) printf("YES\n"); else printf("NO\n"); } }
二分图大佬code:
#include<bits/stdc++.h> using namespace std; const int N = 2e5 + 10; vector<int> g[N],vec[N]; bool vis[N]; int col[N]; bool ok = true; void dfs(int u){ vis[u] = 1; for(auto v:g[u]){ if(!vis[v]){/*如果尚未涂色,那就涂成与上一张牌不同的颜色,因为每条边连的是包含相同数字的牌*/ col[v] = 1-col[u]; dfs(v); } else if(col[v] == col[u]) ok = false; } } void solve() { int n; ok = true; cin>>n; for(int i = 1;i <= n;++i)g[i].clear(),vec[i].clear(),vis[i] = 0; for(int i = 1;i <= n;++i){ int a,b; cin>>a>>b; vec[a].push_back(i); vec[b].push_back(i);/*记录每个数字在第几张牌上*/ if(a==b) ok = false;/*同一张牌上的数字不同*/ } for(int i = 1;i <= n;++i) if(vec[i].size()!=2) ok =false;/*每个数字出现的次数刚好为2*/ if(!ok){ cout<<"NO"<<endl; return; } for(int i = 1;i <= n;++i){ int u = vec[i][0],v = vec[i][1]; g[u].push_back(v); g[v].push_back(u);/*将包含相同数字的牌连起来*//*例如:{1,2}->{2,3}->{3,5}*/ } for(int i = 1;i <= n;++i){ if(!vis[i]){ col[i] = 1;/*涂色*/ dfs(i); } } if(ok) cout<<"YES"<<endl; else cout<<"NO"<<endl; } int tt; signed main() { cin >> tt; while (tt--)solve(); }