#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #define INPUT using namespace std; /* Problem : HDU1272 - 小希的迷宫 State : 5421320 2012-02-26 23:40:14 Accepted 1272 62MS 1636K 3853 B G++ c0de4fun Begin Time:26th/2/2012 9:30 p.m; End Time:26th/2/2012 11:43 p.m Cost Time: 2 hrs 13 mins; 测试数据: 1 4 1 2 2 12 12 13 12 15 15 11 11 3 3 2 4 5 5 9 5 6 6 7 6 8 9 10 0 0 1 2 1 3 1 4 2 8 8 9 3 5 5 10 10 12 4 6 6 11 4 7 0 0 1 2 3 1 4 1 8 2 8 9 5 3 5 10 10 12 6 4 6 11 4 7 0 0 1 4 2 1 2 12 12 13 15 12 15 11 11 3 2 3 4 5 5 9 5 6 6 7 6 8 9 10 0 0 6 8 5 3 5 2 6 4 5 6 0 0 8 1 7 3 6 2 8 9 7 5 7 4 7 8 7 6 0 0 3 8 6 8 6 4 5 3 5 6 5 2 0 0 1 2 3 4 0 0 1 2 0 0 -1 -1 Output: No Yes Yes No Yes Yes No No Yes 思路: 考察并查集。 每增添一个元素,都要压缩路径,将其parent压缩到顶点。 注意,压缩路径不能采用递归的方式,否则会Exceeded。 压缩路径用while的方式。 每读入一对i,j时有三种情况: (1)i存在,j不存在 这时候j是新增加的元素 nodes[j].parent = findSet(nodes[i]); 就可以,顺便把nodes[i]的parent更新,并且 counts++,增加统计数据,还要统计Rank. nodes[nodes[j].parent].rank++; 每个“代表”的Rank就是其集合中的元素数目,会有用的 (2)j存在,i不存在 跟(1)一样,只不过是 nodes[i].parent = findSet(nodes[j]); counts++; nodes[nodes[i].parent].rank++; (3)j存在,i存在 这不太好办 首先判断nodes[j].parent 是否等于 nodes[i].parent 如果是的话,那么fail = true; 如果不是的话 调用Union,Union分别找到j,i的parent 然后Linked双方的Parent,Parent的Rank较大一方成为 新集合的“代表”,较大一方的Rank更新,同时head指向 较大一方 (4)i,j都不存在 这里我们默认j的parent = i, 【但是没有调用findSet!!!!】 所以 head = i!! —————————————————————————— 需要注意的是,每次调用findSet的时候,需要返回 压缩路径之后的“代表”的下标。以便判断两个已有集合代表 是否相同,同时,还要更新head指针,使其指向该代表。 以便通过代表的Rank和总的元素个数count判断是否只存在 一个集合,如果存在两个集合,那么就Fail = true; 注意,i,j都不存在的时候head = i 否则 1 2 0 0会输出No ——————————————————————————— 结果的判断 只要判断目前head指向的代表的Rank 是否小于 count就可以判断出来 fail,如果小于,那么fail = true; 还有要注意的是fail在i存在,j存在的每次findSet之后也会判断一次 if(fail) print No else print Yes Have fun,c0de4fun. */ const int MAX_SIZE = 100010; struct node { int parent; int val; int rank; }; node nodes[MAX_SIZE]; int allRank = 0; //bool Unioned = false; bool fail = false; int head = 0; void Link(int x,int y) { if(nodes[x].rank > nodes[y].rank) { nodes[y].parent = x; nodes[x].rank = nodes[x].rank + nodes[y].rank; allRank = nodes[x].rank; head = x; } else { nodes[x].parent = y; nodes[y].rank = nodes[y].rank + nodes[x].rank; allRank = nodes[y].rank; head = y; } } int findSet(node* n) { node tmp; tmp = *n; while(tmp.val != tmp.parent) { tmp = nodes[tmp.parent]; } n->parent = tmp.val; head = tmp.val; return tmp.val; } void Union(node *i,node *j) { // Unioned = true; Link(findSet(i),findSet(j)); } int main(int argc,char* argv[]) { int i,j,count = 0; #ifdef INPUT freopen("b:\\acm\\hdu1272\\input.txt","r",stdin); #endif while(scanf("%d%d",&i,&j)!= EOF) { if( i != - 1 && j != -1) { if( i != 0 && j != 0 ) { //Judge if i already existed. if(nodes[i].val == 0) { //Not Existed. //makeSet(nodes[i]) nodes[i].parent = i; nodes[i].val = i; nodes[i].rank = 1; count++; if(nodes[j].val == 0) { nodes[j].parent = i; nodes[j].val = j; nodes[i].rank++; head = i; count++; } else { //node[i].parents = j! // nodes[i].parent = findSet(&node[j]); nodes[i].parent = findSet(&nodes[j]); nodes[i].val = i; nodes[nodes[i].parent].rank++; } } else //Already Existed { // nodes[j].parent = i; if(nodes[j].val != 0) { // To see if nodes[j] existed //Yes nodes[j].val = j; // nodes[j].parent = i; findSet(&nodes[j]); if (nodes[j].parent == nodes[i].parent) fail = true; else Union(&nodes[j],&nodes[i]); } else { //No nodes[j].parent = i; nodes[j].val = j; findSet(&nodes[j]); nodes[nodes[j].parent].rank++; count++; } } } else { /* if(Unioned) { if(allRank < count) fail = true; } */ //head没判断明白! if(nodes[head].rank < count) fail = true; if(fail) printf("No\n"); else printf("Yes\n"); ////Judge now¡ü fail = false; allRank = 0; count = 0; Unioned = false; head = 0; memset(nodes,0,sizeof(node)*MAX_SIZE); } } } return 0; }