ural 1003 Parity

转自:http://hi.baidu.com/jhbuuwehgimnprr/item/99b40d0b452242d11ff04605

 

 

哈希+并查集。

 

首先这道题需要一点点问题的转化,根据奇数偶数的性质“两个奇(偶)数的和差是偶数,一个偶数与一个奇数的和差是奇数”,如果设原01序列为a[1..n],再设sum[i]=a[1]+a[2]+..a[i],那么第i项到第j项的和a[i]+a[i+1]+...+a[j]就等于sum[j]-sum[i-1],于是“i j even”这类信息就等价于“sum[j]-sum[i-1]的值是偶数”,这句话又等价于“sum[j]跟sum[i-1]同奇偶”,所以每条类似“i j even”之类的信息都可以转化成sum[i-1]与sum[j]之间奇偶关系的信息。

定义一堆集合:(i=0..n,所以共有2*n+2个集合哈)
same[i]={x|sum[x]与sum[i]同奇偶}(即i的朋友集)
diff[i]={x|sum[x]与sum[i]不同奇偶}(即i的敌人集)

题意要求我们找出不合逻辑的信息,怎样的信息是不合逻辑的?我们可以考虑这种策略,一条一条读入信息,边读入边处理这两大堆集合,如果读入“i j even”,表示sum[i-1],sum[j]两者同奇偶,则两者的“朋友”与“敌人”也是性质相同的,因此合并集合(diff[i-1]与diff[j])、(same[i-1]与same[j]);如果读入“i j odd”,虽然不同奇偶,但因为奇数偶数非此即彼,于是把一者的朋友与另一者的敌人合并,把一者的敌人与另一者的朋友合并,合并集合(diff[i-1]与same[j])、(diff[j]与same[i-1])。

检测矛盾的办法是当合并以前发现两个待合并的集合已经分属于两个不同集合,也就是说以前的信息已经得出了与这条信息相反的结论,那么这条信息是错误的,这里就是矛盾,输出到这里以前的信息都是“真话”就行了。 

 

编程实现的时候当然要使用并查集,还有几个小问题(这题真够麻烦的=_=),一是这是个关于两类集合的问题,而且这两类集合之间还会有跨越的联系,传统方法直接开两个数组实现并查集只是实现两类独立的集合,这里可以把两个集合放到一个数组里面,并排,于是两个集合之间的链接就方便多了(貌似叫做朋友敌人并查集?);另外就是数据范围很大,不妨用hash存储解决这个问题。

附上本人的拙劣程序,欢迎大家批评.

 

 

 1 #include<iostream>
 2 #include<string>
 3 const int BLOCK=10000;
 4 const int HASHTHING=6000;
 5 int hashTable[20000];
 6 int father[20000]; //0..9999 , 10000..19999
 7 int Hash(int number)
 8 {
 9     int pos=number % HASHTHING;
10     while(hashTable[pos]!=-1 && hashTable[pos]!=number) pos=(pos+1)%HASHTHING;
11     hashTable[pos]=number;
12     return pos;
13 }
14 int Find(int x)
15 {
16     int root=x;
17     while(root!=father[root]) root=father[root];
18     while(x!=root)
19     {
20         int temp=father[x];
21         father[x]=root;
22         x=temp;
23     }
24     return root;
25 }
26 void Union(int x,int y)
27 {
28     int p=Find(x);
29     int q=Find(y);
30     if (p!=q)
31         father[p]=q;
32 }
33 int main()
34 {
35     while(true)
36     {
37         int len;
38         std::cin>>len;
39         if(len==-1) break;
40         
41         int n;
42         std::cin>>n;
43         memset(hashTable,0xff,sizeof(hashTable));
44         for(int i=0;i<20000;++i) father[i]=i;
45         int count;
46         for(count=1;count<=n;++count)
47         {
48             int a,b;
49             std::string signal;
50             std::cin>>a>>b>>signal;
51             bool even=(signal=="even");
52             a=Hash(a-1);
53             b=Hash(b);
54             if(even)
55             {
56                 if(Find(a)==Find(b+BLOCK)) break;
57                 Union(a,b);
58                 Union(a+BLOCK,b+BLOCK);
59             }else{ //odd
60                 if(Find(a)==Find(b)) break;
61                 Union(a,b+BLOCK);
62                 Union(a+BLOCK,b);
63             }
64         }
65         int ans=count-1;
66         {
67         int tempa,tempb;std::string tempstr;
68         for(++count;count<=n;++count)
69             std::cin>>tempa>>tempb>>tempstr;
70         }
71         std::cout<<ans<<std::endl;
72     }
73     return 0;
74 }

 

posted on 2012-12-08 12:41  Acmer_Roney  阅读(370)  评论(0编辑  收藏  举报

导航