题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5486
题意:
给你每个元素一开始所属的集合和最后所属的集合,问有多少次集合的分离操作,并操作和不变操作。
分离:[m1,m2,m3]->[m1],[m2],[m3]
合并:分离的逆操作
不变:[m1,m2,m3]->[m1,m2,m3]
题解;
以集合为单位建图,(一个元素从集合s1到s2则建一条边连接集合s1,s2,注意要删除重边)
然后对于每个点,与它相邻的点如果入度都为1,则为分离操作,
把图转置,再跑一遍分离就是合并。
如果一个集合只有一条连向自己的边,那么说明它是1:1操作。
代码:
#include<iostream> #include<cstdio> #include<map> #include<vector> #include<algorithm> #include<cstring> using namespace std; const int maxn = 1e6 + 10; int n,_max; map<pair<int, int>, int> mp; vector<int> G[maxn], G2[maxn]; int in[maxn], in2[maxn]; void init() { _max = -1; mp.clear(); for (int i = 0; i <maxn; i++) G[i].clear(),G2[i].clear(); memset(in, 0, sizeof(in)); memset(in2, 0, sizeof(in2)); } int main() { int tc,kase=0; scanf("%d", &tc); while (tc--) { scanf("%d", &n); init(); for (int i = 0; i < n; i++) { int u, v; _max = max(_max, u); _max = max(_max, v); scanf("%d%d", &u, &v); if (!mp[make_pair(u, v)]) { mp[make_pair(u, v)]++; G[u].push_back(v); in[v]++; G2[v].push_back(u); in2[u]++; } } int ans1=0, ans2=0,ans3=0; for (int i = 0; i <= _max; i++) { int su = 1; for (int j = 0; j < G[i].size(); j++) { int v = G[i][j]; if (in[v] > 1) { su = 0; break; } } if (su) { if (G[i].size() == 1) ans3++; else if(G[i].size()>1) ans2++; } } for (int i = 0; i <= _max; i++) { int su = 1; for (int j = 0; j < G2[i].size(); j++) { int v = G2[i][j]; if (in2[v] > 1) { su = 0; break; } } if (su) { if (G2[i].size() == 1); else if(G2[i].size()>1) ans1++; } } printf("Case #%d: %d %d %d ", ++kase, ans2,ans1, ans3); } return 0; }