/* WA,但是不知道原因 题意:2*n个同学,n个男生,n个女生,m组数据表示两同学之间没有争吵,女同学中f组朋友。女同学寻找男朋友,如果他们之间或者她的朋友与那个男生之间无争吵,则可以作男朋友。当所有女生都找到男朋友后,则完成一轮。问最终有多少轮。 题解:匈牙利算法 + 并查集 问题显然是二分图最大匹配问题,如果最大匹配为n,则完成一轮。每完成一轮,需要进行一些处理,相同女同学不能选择同样的男生作为男朋友。因为女同学朋友之间是相互的,用并查集可以得到很好地解决。 */ #include <iostream> #define re(i, n) for(int i = 0; i < n; ++ i) using namespace std; const int nMax = 105; int p[nMax]; int link[nMax]; int useif[nMax]; int map[nMax][nMax]; //int fhash[nMax][nMax]; int T, n, m, f; int find(int x)//并查集 { return p[x] == x ? x : p[x] = find(p[x]); } int getPath(int t)//寻找增广路经 { re(i, n) { if(!useif[i] && map[t][i]) { useif[i] = 1; if(link[i] == -1 || getPath(link[i])) { link[i] = t; return 1; } } } return 0; } int getNum()//匈牙利算法,匈牙利算法最坏复杂度O(N^3) { int sum = 0; memset(link, -1, sizeof(link)); re(i, n) { memset(useif, 0, sizeof(useif)); sum += getPath(i); } if(sum == n) re(i, n) { map[link[i]][i] = 0; } return sum; } int main() { //freopen("f://data.in", "r", stdin); scanf("%d", &T); while(T --) { scanf("%d %d %d", &n, &m, &f); int a, b; re(i, m) { scanf("%d %d", &a, &b); -- a; -- b; map[a][b] = 1; } re(i, n) p[i] = i; re(i, f) { scanf("%d %d", &a, &b); -- a; -- b; if(find(a) != find(b)) p[a] = find(b); } /* re(i, n) re(j, n)//这里曾经出错,第二个误写成re(j, m),纠结了好久 { if(map[i][j]) { map[find(i)][find(j)] = 1; } }*/ re(i, n)//朋友间关系的处理,如果i和j互为朋友,且j和k无争吵,则i和k也无争吵 { int si = find(i); re(j, n) if(i != j && si == find(j)) re(k, n) if(map[j][k]) map[i][k] = 1; } //memset(fhash, 0, sizeof(fhash)); int ans = 0; while(getNum() == n) ans ++; printf("%d\n",ans); } return 0; }