展示了并查集的使用
使用思路是这样的,首先可能有多少个点就初始化多少个并查集,并记录此时并查集个数;
然后再对有边的两个点判断属于哪一个并查集,如果不在同一个并查集,那么就合并这两个并查集;
最后看并查集的个数是不是1,当然要排除那些没有出现的点。
另一个有趣的地方是这里degree的使用,它并没有区分是入度还是出度。因为我们最后要的结果是出入度的差。
下面贴上 代码
//此题使用并查集的方式来判断是否联通 #include<cstdio> #include<cstring> //using namespace std; int p[26]; char letter[1005]; int findset(int x) { if(p[x] == x) { return x; } int y = findset(p[x]); p[x] = y; return y; } int main() { #ifdef local freopen("input.txt","r",stdin); freopen("out.txt","w",stdout); #endif int kase; scanf("%d",&kase); for(int i_1 = 0; i_1 < kase;i_1++) { int num_letter; scanf("%d",&num_letter); //首先得初始化并查集 int degree[26]; int exist[26];//还需要判断某个节点出现与否 memset(degree,0,sizeof(degree)); memset(exist,0,sizeof(exist)); int cc = 26; for(int i_2 = 0; i_2 < 26;i_2++) { p[i_2] = i_2; } for(int j_1 = 0;j_1 < num_letter; j_1++) { scanf("%s",letter); int len = strlen(letter); degree[letter[0] - 'a']--; degree[letter[len - 1] - 'a']++; exist[letter[0] - 'a'] = 1; exist[letter[len - 1] - 'a'] = 1; int x1 = findset(letter[0] - 'a'); int x2 = findset(letter[len - 1] - 'a'); if(x1 != x2) { p[x1] = x2; cc--; } } int flag = 0; int pos; for(int i_3 = 0;i_3 < 26;i_3++) { if(!exist[i_3]) { cc--; } if(degree[i_3]) { flag++; pos = i_3; } } if(cc == 1 && (flag == 0 ||(flag == 2 && (degree[pos] == 1 || degree[pos] == -1)))) { printf("Ordering is possible.\n"); } else { printf("The door cannot be opened.\n"); } } return 0; }