Day6 && Day7

A - How Many Answers Are Wrong

题意:
已知区间[1,n],给出m组数据,即[l,r]区间内数据之和为s,求错误数据的数量。

拿到这道题,真的没思路,知道用并查集,但是关于如何定义s迟迟没有思路,就开始了搜文章学习(划水)的历程。

下面就记录一些自己的体会:

1、并查集中路径压缩的过程中如何更新关系域是关键;

2、根据数据定义一些合理的关系(如:集合中的根与集合中的元素的关系),才能对集合进行合并。这里可能会分一些情况讨论,最终应该是可以化简的。

然后放出学习的文章(感谢作者):

1、hdu 3038(扩展并查集)

2、POJ-1182 食物链

里面有关向量的思考和设计很巧妙

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 using namespace std;
 5 const int maxn = 200020;
 6 int f[maxn];
 7 int sum[maxn];   //记录当前结点到根的距离
 8 int find(int x){
 9 //return x==f[x]?x:find(f[x]);    
10     if(x != f[x]){
11         int roota = f[x];
12         f[x] = find(f[x]);
13         sum[x] += sum[roota];
14         //x->rootb = x->roota + roota->rootb 
15     }
16     return f[x];
17 }
18 int main(){
19     //freopen("in.txt","r",stdin); 
20     int n,m;
21     while(scanf("%d%d", &n, &m) != EOF){
22         for(int i=0; i<=n; i++){
23             f[i] = i;
24             sum[i] = 0;
25         }
26         int ans = 0;
27         while(m--){
28             int a, b, v;
29             scanf("%d%d%d", &a, &b, &v);
30             a--;
31             //join 
32             int roota = find(a);
33             int rootb = find(b);
34             if(roota == rootb){
35                 if(sum[a]-sum[b] != v)    ans++;
36             }else{
37                 f[roota] = rootb;
38                 //定义大的数字是小的数字的根 
39                 sum[roota] = -sum[a] + sum[b] + v;
40                 //变换成等式 sum[roota] + sum[a] = sum[b] + v;
41                 //a->roota + roota->rootb == b->rootb + a->b 
42             }
43             //join
44         }
45         printf("%d\n",ans);
46     }
47     return 0;
48 }

B - 食物链

摘出上博客中的一句话:

对于集合里的任意两个元素x,y而言,它们之间必定存在着某种联系,因为并查集中的元素均是有联系的(这点是并查集的实质),否则也不会被合并到当前集合中。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 const int maxn = 50010;
 6 int f[maxn], relation[maxn];
 7 //relation[i]:i到根的偏移量 
 8 int sum;
 9 void init(int n){
10     for(int i=0; i<n; i++){
11         f[i] = i;
12         relation[i] = 0;
13     }
14     sum = 0;
15 }
16 int find(int x){
17     if(x != f[x]){
18         int rootx = f[x];
19         f[x] = find(rootx);
20         //路径压缩更新关系域//这是关键1 
21         relation[x] = (relation[x] + relation[rootx]) % 3;
22     }
23     return f[x];
24 }
25 void join(int x, int y, int d){
26     int rootx = find(x);
27     int rooty = find(y);
28     if(rootx != rooty){
29         f[rooty] = rootx; 
30         relation[rooty] = (3 + d-1 + relation[x] - relation[y]) % 3;
31         //此处d-1题中给出的询问已知条件即0同类,1吃,2被吃
32         /*先用等式表达:
33         这里并非简单的加减,实质应该是关系的转移,可以用向量理解 
34              r->rx + x->y = y->ry + ry->rx
35         ====>r[x] + k = r[y] + ry->rx
36         ====>ry->rx = r[x] + k - r[y]
37            k = d - 1 
38            同理下面两式也得 
39         */ 
40     }else{
41         if((d==1) && (relation[x] != relation[y])){
42             sum++;
43         }else if((d==2) && ((d-1) != (relation[y] - relation[x] + 3) % 3)){
44             sum++;
45         }
46     }
47 }
48 int main(){
49     //freopen("in.txt","r",stdin); 
50     int n, k;
51     scanf("%d%d", &n, &k);
52     init(n);
53     for(int i=0; i<k; i++){
54         int d, x, y;
55         scanf("%d%d%d",&d, &x, &y);
56         if(x > n || y > n){
57             sum++;
58         }else if((d==2) && (x == y)){
59             sum++;
60         }else{
61             join(x, y, d);
62         }
63     }
64     printf("%d\n",sum);
65     return 0;
66 }

 C - A Bug's Life

题意:给定n个bugs,编号依次1、2、……n。它们之间只有雄性和雌性之分,并给定m对交配的情况,根据这m对交配的情况,判断是否有同性恋出现的情况。

Thinking:

定义relation[i]:结点i到根的距离:即相对与根节点的性别。

x,y在同一集合,他们相对根的距离即相对根的性别,而他们又同根,易得x,y的相对性别

x,y不再同一集合,思考向量得关系: y->x + x->rootx = y->rooty + rooty->rootx 其中y->x应为1。

 1 #include <cstdio>
 2 const int maxn = 2010;
 3 int f[maxn];
 4 int relation[maxn];
 5 bool flag;
 6 void init(int n){
 7     //这里n没有初始完( i < n )导致WA了半天 
 8     for(int i=0; i<=n; i++){
 9         f[i] = i;
10         relation[i] = 0;
11     }
12 }
13 int find(int x){
14     if(x != f[x]){
15         int rootx = f[x];
16         f[x] = find(rootx);
17         relation[x] = (relation[rootx] + relation[x]) % 2;
18     }
19     return f[x];
20 }
21 void join(int x, int y){
22     int rootx = find(x);
23     int rooty = find(y);
24     if(rootx == rooty){
25         if(relation[x] == relation[y]){
26             flag = true;
27         }
28     }else{
29         /*A了这题后在网上看到很多解法中这里对x,y进行分类, 
30         即 x<y  : 
31                 f[rooty] = rootx;
32                 relation[rooty] = ((relation[x]+1) + relation[y]) % 2;
33           x>y    :
34                    f[rootx] = rooty;
35                 relation[rootx] = ((relation[y]+1)%2 + relation[x]) % 2;
36             这里我认为应该可以不需要,因为查找过程中进行了路径压缩 
37         */ 
38         f[rooty] = rootx;
39         relation[rooty] = ((relation[x]+1) - relation[y]) % 2;
40             //这里+由向量y->x + x->rootx = y->rooty + rooty->rootx得应该是-,但%2好像算术上是等价的
41             //这里我个人认为是减,当然%2时加和减结果一样, 这里留待思考????? 
42     }
43 }
44 int main(){
45     //freopen("in.txt","r",stdin); 
46     int T;
47     scanf("%d", &T);
48     for(int t=1; t<=T; t++){
49         int b, inter;
50         scanf("%d%d",&b, &inter);
51         init(b);
52         flag = false;
53         for(int i=0; i<inter; i++){
54             int x, y;
55             scanf("%d%d", &x, &y);
56             if(flag){
57                 continue;
58             }else{
59                 join(x, y);
60             }
61         }
62         printf("Scenario #%d:\n", t);
63         if(flag){
64             printf("Suspicious bugs found!\n\n");
65         }else{
66             printf("No suspicious bugs found!\n\n");
67         }
68     }
69     return 0;
70 }

D - Supermarket 

并查集,不太想做了,以后补

猜你喜欢

转载自www.cnblogs.com/seaupnice/p/9440137.html
今日推荐