nput
3 0
Output
3 2 1
Input
6 4
1 2
2 3
3 4
5 6
Output
-1
Input
3 3
1 2
2 3
1 3
Output
3 2 1
题意是:有一群人要组队,如果a想和b一队,b就得和a一队。给出组队愿望,打印出一组符合的组队形式,如果不能就输出-1.
每队3个人,每一行输出这队的成员;
我是这样想的,这样的题应该不假思索的用并查集吧,一开始我也用了,但是最后输出的时候好麻烦啊,因为,例如如果输入关系1 2 1 3 这样用并查集做f[1] = 2,f[2] = 3,f[3] = 3.输出的时候为了找到同一个一队的人就不是很方便了,而且还会有人没有发表过意见,这种情况处理起来也不是很容易(说到底还是我渣,大神们用并查集写的代码也很简单)于是我就换了一种方法,好在最大的人数只有48 3重循环也不怕!我做的改动是使得同一个队的父亲节点只有一个(暂且叫他队长好了)即f[1] = 3;f[2] = 3;f[3] = 3;然后为了处理无法组队的情况又开了一个数组q,用于记录第i个人所在的队已经有q[i]个人了,最后还是错了两次,一次是错在测试样例6 3 1 2 3 4 5 6 上,这样一组测试样例应该输出-1才对,我却输出1 2 3 4 5 6 因为我没有在最后再一次检验是否能够组队成功,一次错在 9 3 4 5 6 7 8 9上因为我一开始遇见没有意见的人就从前向后遍历找到一个没有组队的或者队里不满的就组队。这样的结果就是1 2 3 4 5 6 7 8 9显然错了,于是我又让没有意见的人先加入人数不满的队中,剩下的再自己组队。这样就过了。
#include<stdio.h> int main() { int q[52] = {0}; int f[52]; int N,T,i,j,k; scanf("%d%d",&N,&T); int a,b; int flag = 0; for(i = 1;i <= N;i++)f[i] = i; while(T--) { scanf("%d%d",&a,&b); if(q[a] == 0 && q[b] == 0)q[a] = 2; else if(q[a]== 0 &&q[b] != 0)q[a] = q[b]+1; else if(q[a] != 0 && (f[a] != b&&f[b]!= a)) q[a]++; q[b] = q[a]; if(f[a] == a) { for(i = 1;i <= N;i++) { if(f[i] == a)f[i] = b; } for(i = 1;i <= N;i++) { if(f[i] == b)q[i] = q[a]; } } else {q[f[a]] = q[a];f[f[a]] = b;f[a] = b;} } for(i = 1;i <= N;i++)if(q[i] > 3) {flag = 1;break;} if(flag == 1)printf("-1\n"); else { for(i = 1;i <= N;i++)//处理有人没有意见的情况,优先补满缺一个人的队 { if(q[i] == 0)//没有意见 { for(j = 1;j <= N;j++) { if(j == i)continue; if(q[j] == 2)//该组已经有2个人 { q[j]=q[i] = 3; if(f[j] == j)//这个人是队长 { for(k = 1;k <= N;k++) { if(f[k] == j)q[k] = 3;//找到队员 } f[i] = j; } else {q[f[j]] = 3;f[i] = f[j];} break; } } } } int c,num= 0; for(i = 1;i <= N;i++) { if(q[i] == 0) { if(num == 0) {num++;a = i;continue;} if(num == 1) {num++;b = i;continue;} if(num == 2) {f[a] = f[b] = i;q[a] = q[b] = q[i] = 3;num = 0;continue;} } } for(i = 1;i <= N;i++) { if(q[i] != 3){printf("-1\n");return 0;} } for(i = 1;i <= N;i++) { if(f[i] == i) { for(j = 1;j <= N;j++) { if(f[j] == i) printf("%d ",j); } printf("\n"); } } } return 0; }