专栏文章

[P8346] 「Wdoi-6」最澄澈的空与海 题解

P8346题解参与者 2已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@mioy9o9v
此快照首次捕获于
2025/12/03 03:07
3 个月前
此快照最后确认于
2025/12/03 03:07
3 个月前
查看原文
直接考虑是非常困难的,考虑找到一个薄弱环节。
发现度数为 11 的结点 uu 只能匹配其所连的边 (u,v)(u,v) 对应的结点 vv。结点 vv 被匹配后,其连边都没有用了,可以直接删去。这样一来,可能产生新的度数为 11 的结点。如此循环,最终剩下若干个连通块。这个过程可以使用类似拓扑排序的方式实现。
考察一个留下来的连通块,若其点数为 11 则原图存在孤立点,必然无解。否则,其所有节点必然满足度数 2\ge 2,于是必然存在一个大小 2\ge 2 的环。
证明:连通,其必然能够取出一颗生成树,考虑树上任意一个度数为 11 的叶子,其另一条连边一定与这颗生成树上的边构成一个大小 2\ge 2 的环。
二分图,得到的环是偶环,对环上的边进行黑白染色,可以得到两种方案:用黑边匹配或用白边匹配。
所以如果有剩余连通块,即删边过程中有点没有被匹配,要么无解要么多解。
时间复杂度:O(n+m)\mathcal{O}(n+m)
2025.11.19 upd:修改了代码使其通过 hack,思路没有变动。
codeCPP
#include<bits/stdc++.h>
#define pb emplace_back
using namespace std;
typedef long long ll;
const ll maxn=2000007,p=998244353,B=14;
ll n,m,deg[maxn],vis[maxn],q[maxn],h,t;
vector<ll> edge[maxn];
void bfs(void){
	h=0,t=1;
	for(int i=1;i<=2*n;i++)if(deg[i]==1) q[++h]=i;
	for(ll u;h>=t;){
		u=q[t],t++;
		for(auto v:edge[u])if(!vis[v]){
			vis[v]=vis[u]=1;
			for(auto w:edge[v])if(!vis[w]){
				deg[w]--;
				if(deg[w]==1) q[++h]=w;
			}
		}
	}
}
string solve(void){
	bfs();
	for(int i=1;i<=2*n;i++)if(!vis[i]) return "Merry";
	return "Renko";
}
int main(void){
	//freopen("data.in","r",stdin);
	//freopen("data.out","w",stdout);
	ios::sync_with_stdio(0),cin.tie(0);
	ll T=1; cin>>T;
	for(;T--;){
		for(int i=1;i<=2*n;i++) deg[i]=vis[i]=0,edge[i].clear();
		cin>>n>>m;
		for(int i=1,u,v;i<=m;i++){
			cin>>u>>v,edge[u].pb(v+n),edge[v+n].pb(u);
			deg[u]++,deg[v+n]++;
		}
		cout<<solve()<<"\n";
	}
	return 0;
}

评论

2 条评论,欢迎与作者交流。

正在加载评论...