【并查集缩点+拓扑】Rank of Tetris

Rank of Tetris

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1827    Accepted Submission(s): 487

Problem Description
自从Lele开发了Rating系统,他的Tetris事业更是如虎添翼,不久他遍把这个游戏推向了全球。

为了更好的符合那些爱好者的喜好,Lele又想了一个新点子:他将制作一个全球Tetris高手排行榜,定时更新,名堂要比福布斯富豪榜还响。关于如何排名,这个不用说都知道是根据Rating从高到低来排,如果两个人具有相同的Rating,那就按这几个人的RP从高到低来排。

终于,Lele要开始行动了,对N个人进行排名。为了方便起见,每个人都已经被编号,分别从0到N-1,并且编号越大,RP就越高。
同时Lele从狗仔队里取得一些(M个)关于Rating的信息。这些信息可能有三种情况,分别是"A > B","A = B","A < B",分别表示A的Rating高于B,等于B,小于B。

现在Lele并不是让你来帮他制作这个高手榜,他只是想知道,根据这些信息是否能够确定出这个高手榜,是的话就输出"OK"。否则就请你判断出错的原因,到底是因为信息不完全(输出"UNCERTAIN"),还是因为这些信息中包含冲突(输出"CONFLICT")。
注意,如果信息中同时包含冲突且信息不完全,就输出"CONFLICT"。

 

Input
本题目包含多组测试,请处理到文件结束。
每组测试第一行包含两个整数N,M(0<=N<=10000,0<=M<=20000),分别表示要排名的人数以及得到的关系数。
接下来有M行,分别表示这些关系

 

Output
对于每组测试,在一行里按题目要求输出

 

Sample Input
3 3
0 > 1
1 < 2
0 > 2
4 4
1 = 2
1 > 3
2 > 0
0 > 1
3 3
1 > 0
1 > 2
2 < 1 
Sample Output
OK
CONFLICT
UNCERTAIN
 

解法:

  蛮不错的一道经典题,不过题目有一点没理解好的是,当 A=B 的时候表示的是A和B的Rating是一样的,共用一个位置的(比如都在11名的话,他们两个的排名都是11,而不是一个11名一个12名),而他们两的相对位置和标号有关而已。也就是Rating不是唯一的,同一个Rating可能存在多个人,同一Rating的人则是按照编号大到小优先排序。

  这道题目所要求的是,根据所给的信息,能否判断出是否能够构成Rating表。有三种情况,可行OK,信息不足UNCERTAIN,信息存在冲突CONFLICT。由于只要判断能否构建Rating表,所以,只需要判断能否拓扑即可,对于同一Rating的人顺序位置,不需要知道。在信息不冲突情况下,都能够拓扑排序即可、

  因为Rating是不唯一的,可以把同一个Rating的人都看做一个人,也就是对所给的信息进行缩点,用并查集维护即可。如果一个人的Rating是一样的,当两个人在出现>或者<的时候,则可以判断信息出现冲突了。因为>或者<的出现表示两个数不可能是同一个Raring。在缩点之前,需要先把所有输入的信息先保存下来,先把Rating相等的点,进行缩点处理,再去判断输入的信息是否冲突。(PS:可以理解缩点后的Rating都是唯一的)

  这一题的话,还需要判断重边和环的情况。当然,你用队列+邻接表来进行拓扑排序的话,则不需要进行这些处理了,详细见代码解释、

  用队列进行拓扑排序的话,可以很好的判断三种条件:

         1.当队列Q.size() > 1,表明所给的信息不足,因为有多个入度为0的点,无法判断先后顺序(不同Rating的人不是按编号排序的!!!)。

         2.当队列结束后,剩余的缩点数n>0,说明出现环时,排名有冲突。

         3.若进队列次数等于n,证明可以知道此图是单向无环图。

代码:2015.8.6(并查集缩点+拓扑+队列)

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <map>
 5 #include <queue>
 6 #define MAX 10010
 7 using namespace std;
 8 int Fa[MAX];
 9 int InD[MAX];
10 int First[MAX];
11 struct edge{int TO,Next;}ID[30*MAX];
12 int SIGN;
13 void Add_E(int x,int y)
14 {
15     ID[SIGN].TO=y;InD[y]++;
16     ID[SIGN].Next=First[x];
17     First[x]=SIGN++;
18 }
19 void Cread(int N)
20 {
21      for(int i=1;i<=N;i++){First[i]=0;InD[i]=0;Fa[i]=i;}
22 }
23 int Find(int x)
24 {
25     if(x!=Fa[x])Fa[x]=Find(Fa[x]);
26     return Fa[x];
27 }
28 int Link_P(int x,int y)
29 {
30     int A=Find(x);
31     int B=Find(y);
32     if(A!=B){Fa[A]=B;return 1;}
33     else return 0;
34 }
35 void ToPoSort(int N,int NUM)/*N为点数,NUM为剩余的缩点数*/
36 {
37     int i,j,k,sign=0;
38     queue <int>Que;
39     for(i=1;i<=N;i++)
40     {
41         if(InD[i]==0&&i==Find(i))/*用并查集缩点则需要判断的是缩点*/
42             Que.push(i);
43     }
44     while(!Que.empty())
45     {
46 
47         if(Que.size()>1)sign=1;/*存在两个入度为0的点,表示信息不完全*/
48         k=Que.front();Que.pop();
49         NUM--;InD[k]--;
50         for(i=First[k];i!=0;i=ID[i].Next)/*出现重边时候也会多减*/
51         {
52             if(--InD[ID[i].TO]==0)/*将入度为0的点进队列*/
53             {
54                 Que.push(ID[i].TO);
55             }
56         }
57     }
58     if(NUM){printf("CONFLICT\n");}/*剩余的缩点数>0时,表示出现环时*/
59     else if(sign){printf("UNCERTAIN\n");}/*信息不具体*/
60     else {printf("OK\n");}
61     return ;
62 }
63 int main()
64 {
65     int M,N,i,T,k,j,NUM,A,B;
66     int a[MAX],b[MAX];
67     char str[MAX];
68     while(scanf(" %d %d",&N,&M)!=EOF)
69     {
70         Cread(N);NUM=N;SIGN=1;/*NUM记录缩点后的点数*/
71         for(i=0;i<M;i++)
72         {
73             scanf(" %d %c %d",&a[i],&str[i],&b[i]);
74             a[i]++;b[i]++;/*变成编号为1~N的数*/
75             if(str[i]=='=')
76             {
77                 if(Link_P(a[i],b[i]))
78                     NUM--;/*缩点后的数减1*/
79             }
80         }
81         for(i=0,j=0;i<M;i++)
82         {
83             if(str[i]=='=')continue;
84             A=Find(a[i]);B=Find(b[i]);
85             if(A==B){j=1;break;}
86             if(str[i]=='>')Add_E(A,B);
87             else Add_E(B,A);
88         }
89         if(j){printf("CONFLICT\n");continue;}
90         ToPoSort(N,NUM);
91     }
92     return 0;
93 }
View Code


 代码:2015.8.19(并查集缩点+拓扑+栈)

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <stack>
  5 #include <map>
  6 #define MAX 10010
  7 using namespace std;
  8 int InD[MAX];/*InD[i]记录点i的入度*/
  9 int First[MAX];/*First[i]头结点的第一条边的编号*/
 10 struct edge
 11 {
 12     int TO;/**/
 13     int Next;/*下一条边的编号*/
 14 }ID[3*MAX];
 15 int SIGN;
 16 int Fa[MAX];
 17 int Find(int x)
 18 {
 19     if(x!=Fa[x])Fa[x]=Find(Fa[x]);
 20     return Fa[x];
 21 }
 22 int Link_P(int a ,int b)
 23 {
 24     int A=Find(a);
 25     int B=Find(b);
 26     if(A!=B){Fa[A]=Fa[B];return 1;}
 27     else return 0;
 28 }
 29 
 30 void Add_E(int x,int y)/*添加点操作*/
 31 {
 32     ID[SIGN].TO=y;
 33     InD[y]++;
 34     ID[SIGN].Next=First[x];
 35     First[x]=SIGN++;
 36 }
 37 int Jude(int x,int y)/*查找与X是否与Y相连*/
 38 {
 39     int i;
 40     for(i=First[x];i!=0;i=ID[i].Next)   //查找与该点相关的点
 41     {
 42        if(ID[i].TO==y)return 0;
 43     }
 44     return 1;
 45 }
 46 void ToPoSort(int N,int Num[],int NNN)/*拓扑排序,邻接表*/
 47 {
 48     int i,j,jj,k,sign=0,NN=N-NNN;
 49     int KK,P;
 50     stack<int>s;
 51     for(i=1;i<=N;i++)
 52         if(Find(i)==i&&InD[i]==0)
 53             s.push(i);
 54     while(!s.empty())
 55     {
 56         if(s.size()>1)sign=1;
 57         k=s.top();s.pop();
 58         NN--;InD[k]--;
 59         for(i=First[k];i!=0;i=ID[i].Next)
 60         {
 61             if(--InD[ID[i].TO]==0)
 62                 s.push(ID[i].TO);
 63         }
 64     }
 65     if(NN){printf("CONFLICT\n");}/*剩余的缩点数>0时,表示出现环时*/
 66     else if(sign){printf("UNCERTAIN\n");}/*信息不具体*/
 67     else {printf("OK\n");}
 68 }
 69 int main()
 70 {
 71     int M,N,i,T_T,NNN;
 72     int a[MAX],str[MAX],b[MAX];
 73     int Num[MAX];
 74     while(scanf("%d%d",&N,&M)!=EOF)
 75     {
 76         for(i=1;i<=N;i++){First[i]=0;InD[i]=0;Fa[i]=i;}
 77         for(i=1,NNN=0;i<=M;i++)
 78         {
 79             scanf("%d %c %d",&a[i],&str[i],&b[i]);
 80             a[i]++;b[i]++;
 81             if(str[i]=='=')
 82             {
 83                 if(Link_P(a[i],b[i]))
 84                     NNN++;
 85             }
 86         }
 87         for(i=1,SIGN=1,T_T=0;i<=M;i++)
 88         {
 89             if(str[i]=='=')continue;
 90             else
 91             {
 92                 int A=Find(a[i]),B=Find(b[i]);
 93                 if(A==B){T_T=1;break;}
 94                 else
 95                 {
 96                     if(str[i]=='>')
 97                         {if(Jude(A,B))Add_E(A,B);}
 98                     else
 99                         {if(Jude(B,A))Add_E(B,A);}
100                 }
101             }
102         }
103         if(T_T){printf("CONFLICT\n");continue;}
104         ToPoSort(N,Num,NNN);
105     }
106     return 0;
107 }
View Code

 

PS:虽然是第二次做,刻意换了种方法做,还是多多少少有些细节错误,在用并查集缩点的时候,在添加边的操作的时候,有忘记用缩点后的并查集来代替了的,Orz,Orz,Orz.....

提供一组缩点不注意就容易出错的数据:

/*
3 3
0>1
2>0
1=2

*/

posted @ 2015-08-06 16:54  Wurq  阅读(318)  评论(0编辑  收藏  举报