题意
给定 2n 个点、m 条边的二分图(可能有重边),左部点与右部点个数相同,判断其完美匹配数量是否恰好为 1。是则输出 Renko
,否则输出 Merry
。
注:完美匹配是指,从边集中选出 n 条边,这些边的顶点组成的点集恰好覆盖了所有的 2n 个点。
解法
对于图论的题,尤其是这种题,要关注度(入度)这个关键概念
(无向图没有入度出度之分,入度等于出度,统一为度,开一个数组记录即可)
纸上模拟可知:
对于一个度为1的u点,与他匹配的只能是对应的v点。一组确定的点,不能改变的匹配就这样确定了。用del数组记录已经确定的点的集合
再继续将v点所对应的边都删去,将度为1的点入队,重复上述过程。
统计cnt,如果==2n则唯一确定。
#include<bits/stdc++.h> typedef long long ll; using namespace std; const int N = 2 * 1e6 + 10; int du[N]; vector<int> G[N]; bool del[N]; int main(){ std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int t, cnt; cin >> t; while(t -- ) { cnt = 0; int n, m; cin >> n >> m; //memset(du, 0, sizeof du); //memset(del, 0, sizeof del); for (int i = 0; i < m; i ++ ) { int x, y; cin >> x >> y; G[x].push_back(y + n); G[y + n].push_back(x); du[x]++, du[y + n]++; } queue<int> q; for (int i = 1; i <= 2 * n; i ++ ) { if(du[i] == 1)q.push(i); } while(q.size()) { int u = q.front(); q.pop(); if(del[u] || du[u] != 1) continue; del[u] = 1; cnt ++; int id; for (int i = 0; i < (int)G[u].size(); i ++ ) { if(!del[G[u][i]]) id = G[u][i]; } cnt ++; del[id] = 1; for (int i = 0; i < (int)G[id].size(); i ++ ) { if(del[G[id][i]]) continue; if((-- du[G[id][i]])== 1) { q.push(G[id][i]); } } } cout << (n*2 == cnt ? "Renko" : "Merry") << '\n'; for (int i = 1; i <= 2 * n; i ++ )du[i] = del[i] = 0, G[i].clear(); } return 0; }