题目链接
每次给出两个昆虫的关系(异性关系),然后发现这些条件中是否有悖论
就比如说第一组数据
1 2
2 3
1 3
1和2是异性,2和3是异性,然后说1和3是异性就显然不对了。
我们同样可以思考一下这道题如何用带权并查集去做。
首先用r[x]存储的是x与其根节点rx的关系,0代表同性1代表异性(其实反着也一样因为这个关系是一个环状的)
这道题与上一道题唯一的不同是权值不是累加的关系而是相当于二进制的个位,也就是累加结果取%2。
这样就很容易仿照上一道题写出一下代码
#include<iostream> #include<cstdio> using namespace std; const int maxn = 2000 + 10; int pre[maxn]; int sex[maxn]; int find(int x){ int fx = pre[x]; if(pre[x] != x){ pre[x] = find(pre[x]); //判断与父节点的性别是否相同 sex[x] = (sex[x] + sex[fx]) % 2; } return pre[x]; } int main(){ int flag; int sum = 0; int t; int x,y,n,m; scanf("%d",&t); //cin >> t; while(t--){ flag = 1; scanf("%d%d",&n,&m); for(int i = 0 ; i <= n; i++){ pre[i] = i; sex[i] = 0; } while(m--){ //cin >> x >> y; scanf("%d%d",&x,&y); if(!flag) continue; int fx = find(x); int fy = find(y); if(fx == fy){ //因为都为奇数或是偶数那么同性 if((sex[x] - sex[y]) % 2 == 0){ flag = 0; } } else { pre[fx] = fy; //满足异性 sex[fx] = (sex[x] - sex[y] + 1); } } printf("Scenario #%d:\n",++sum); if(flag) printf("No suspicious bugs found!\n\n"); else printf("Suspicious bugs found!\n\n"); } return 0; } // return 0;
这题可以用二分图做,二分图是来判断两点颜色是否一样。
后续会补上做法。
题解
题目大意: 给你一系列区间和,判断给出的区间中有几个是不合法的。
思考: 1.如何建立区间之间的联系 2.如何发现悖论 首先是如何建立联系,我们可以用一张图表示 假如说区间【fx,x】是之前建立的区间,他们之间和为sum[x],fx和x的联系可以用集合来存储,同理【fy,y】也是如此。
当给出了一个新的区间【x,y】时,且区间和为s。就产生了两种情况了,如果fx == fy 那么这两个区间是有关联的区间,也就是【x,y】之间的和是可以求出的。可以把这个图看成一个向量。
区间【x,y】的和就是可以写成sum[x] - sum[y]。判断给出的s与向量法计算的区间和是否相等就可以判断是否是悖论。 当然如果fx != fy就需要建议新的区间关系。
首先将fy指向fx,这代表fx是区间的左端点,计算sum【fy】= sum【x】- sum【y】+ s;这里同样用的是向量法。 这样建立联系与判断悖论都可以表达了,接下来就是一些细节了,比如在更新区间的时候要进行路径的压缩,压缩的过程中需要对权值进行更新,目的是使每个已知区间最大化。