• POJ1182 食物链


    题目链接:点击打开链接

     

    思路:参考资料后,两种方法:①就是开3倍空间,然后和普通并查集一样,但是关系不太好理解。②向量偏移

    方法一:有好几种理解方式,还是书上的好理解:

    x-A x-B

    x-C

    y-A y-B y-C

    AC代码:

    代码断点1处的 是判断是否b和c不是同类。那么不是同类怎么表示:

    判断x-A 和 y-B 是不是一组,x-A 和 y-C是不是一组。是的话矛盾ans++;

    如果不矛盾,就说明是同类,就合并x-A和y-A , x-B和y-B, x-C和y-C;

    代码断点2处的是判断b是否能吃c,先看是否矛盾,怎么表示矛盾呢:

    首先题目意思:A吃B,B吃C,C吃A。

    矛盾的原因有两个:①同类,②不是同类,但是不符合题目要求;

    例如代码中的    if(findfather(b+n) == findfather(c+n) || findfather(b+2*n) == findfather(c+n))

    这个是判断 是否【b和c都是 B】 或者 【b是C,c是B】这就是对的,因为起到了反例的效果。(说的b吃c,但是C不吃B)

    这个条件只要前面是同类 后面是 吃的反例就是对的。

    例如    if(findfather(b) == findfather(c) || findfather(b+n) == findfather(c))

    是否【b和c都是A】或者【b是B,c是A】也是反例,(说的b吃c,但是B不吃A)

    #include<stdio.h>
    int father[200000];
    const int maxv=50010;
    void intit() {
    	for(int i=0; i<=200000; i++) {
    		father[i]=i;
    	}
    }
    int findfather(int x) {
    	int a=x;
    	while(father[x]!=x) {
    		x=father[x];
    	}
    	while(a!=father[a]) {
    		int z=a;
    		a=father[a];
    		father[z]=x;
    	}
    	return x;
    }
    void Union(int a,int b) {
    	int fa=findfather(a);
    	int fb=findfather(b);
    	if(fa!=fb) {
    		father[fa]=fb;
    	}
    }
    int main() {
    	int n,m,a,b,c,ans=0;
    	scanf("%d%d",&n,&m);
    	intit();
    	for(int i=1; i<=m; i++) {
    		scanf("%d%d%d",&a,&b,&c);
    		if(b < 0 || b > n || c < 0 || c > n || (a == 2 && (b == c))) {//条件
    			ans++;
    			continue;
    		}
    		if(a==1) {//代码断点1
    			if(findfather(b)==findfather(c+n)||findfather(b)==findfather(c+2*n)) {
    				ans++;
    				continue;
    			}
    			else {
    				Union(b, c);
    				Union(b+n, c+n);
    				Union(b+2*n, c+2*n);
    			}
    		}
    		if(a==2) {//代码断点2
    			if(findfather(b+n) == findfather(c+n) || findfather(b+2*n) == findfather(c+n)) {
    				ans++;
    				continue;
    			} else {
    				Union(b, c+n);
    				Union(b+n, c+2*n);
    				Union(b+2*n, c);
    			}
    		}
    	}
    	printf("%d",ans);
    }
    

    方法二:向量偏移;

    参考博客:https://blog.csdn.net/freezhanacmore/article/details/8767413

    之所以叫向量偏移是和向量有关,体现在合并函数

    先看看find函数:a和b的关系r1, b和c的关系r2,那么a和c的关系为(r1+r2)% 3

    打表可以推断出来,(具体参考上面博客)

    再看Union函数,fy合并于fx,那么fy对于fx的关系见下图

    r[fy] = ( -r[y] + (d-1) + r[x])

    推导:设d = 1,y和x同类,y对x关系为0

               设d = 2, x吃y,那么y对x的关系为1, x对y的关系为2

               无论d是多少,y对x的关系都是d-1

    图片中的向量关系可以得出,这就是向量偏移

    可以和我的另一篇对比看一看:https://blog.csdn.net/qq_40932661/article/details/81043876

    AC代码:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int MAXN = 50010;
    
    int father[MAXN];
    int flag[MAXN];
    int n, m, op, u, v, ans;
    //没有用rank数组,可能是因为合并时时固定的,我用rank数组优化,会错
     
    void init(int n) {
    	for(int i = 0; i <= n+1; i++) {
    		father[i] = i;
    		flag[i] = 0;
    	}
    }
    
    int find(int x) {
    	if(x == father[x])
    		return x;
    	int xx = father[x];
    	father[x] = find(father[x]);
    	flag[x] = (flag[x] + flag[xx]) % 3;//   %集合数
    	return father[x];
    }
    
    void Union(int x, int y) {
    	int fx = find(x);
    	int fy = find(y);
    	if(fx == fy)
    		return;
    	father[fy] = fx;
    	flag[fy] = (flag[x] - flag[y] + 3 + (op-1)) % 3;//这个看对应关系。 注意fx,fy,x,y
    }
    
    int main() {
    		scanf("%d%d", &n,&m);
    		init(n);
    		ans = 0;
    		while(m--) {
    			scanf("%d%d%d", &op, &u, &v);
    			if(u <= 0 || u > n || v <= 0 || v > n || (op == 2 && u == v)) { 
    				ans++;
    				continue;
    			}
    			if(find(u) == find(v)) {
    				if((op-1) != (flag[v]-flag[u]+3)%3)//谁减谁,要对应Union操作,这里(father[fy] = fx),换了也可以 。这里特别要注意
    					ans++;
    				continue;
    			}
    			Union(u, v);
    		}
    		printf("%d
    ", ans);
    } 
  • 相关阅读:
    双机调试环境部署
    VC++中通过MultiByteToWideChar将string|char*转换为wstring|wchar_t*
    Unicode环境下的类型转换
    SQL调优日记之发挥SQL性能与你的写法有关--对比三种方式实现相同功能
    从MS SQL删除大数据说开去
    Microsoft SQL Server Reporting Services (SSRS)报表技巧之在图表中增加参考线
    想个法子找出性能差的SQL
    MS SQL,数据库增长时众多表中谁是你关注的目标
    TSQL 日期处理总结
    投入.NET,我的第一篇BLOG
  • 原文地址:https://www.cnblogs.com/ACMerszl/p/9572957.html
Copyright © 2020-2023  润新知