您的位置:首页 > 其它

poj 1703 poj1182(并查集)

2014-08-04 20:57 253 查看
poj1703: 题目大意:有n个人分别属于两个团伙,两种操作 D a b表示a b不在同一团伙,A a b表示询问a b是否在同一团伙
首先要对并查集的基本概念了解,fa[]代表每个元素的父亲是谁,rank[]数组代表的是树的深度,但是根据不同题意会有不同的意义,这个对理解题意很重要。

那么对与这道题,刚开始每个节点都是一棵树,各自的父亲是自己,后来合并,即每个犯罪人都是一个节点,两个人的关系就是一条线,从而逐渐形成一棵树。

这棵树的边相连的两个点是代表不是一个团伙。其实我理解的是深度相同的都属于同一门派,但是这里只有两个门派,所以根据敌人的敌人是朋友的原则,这里rank[]数组的处理就好理解了,所以深度只有0,1.(这种处理方式在下一题会有更好的解释)。

//

//可以把每个人看做一个点 每个关系看做一条边,rank[]本来表示树的深度,在这里表示点之间的权值,两点之间每条线权值为1,
// rank[]依然是深度,表示该点到根节点的深度,如果两个点在同一个集合,并且深度一样,那么就是同一个帮派。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define maxn 100005
int n;
int fa[maxn];
int rank[maxn];
void Init() //初始化
{
	for(int i=0;i<=n;i++)
	{
		fa[i]=i;
		rank[i]=0;
	}

}
int find(int x)
{
	if(fa[x]!=x)
	{
		int father=find(fa[x]);
		rank[x]=(rank[x]+rank[fa[x]])%2;
		fa[x]=father;
		return fa[x];
	}
	 return x;
}
void Union(int x,int y)//合并两个集合 相当于加一条边
{
	int a=find(x);
	int b=find(y); //find 的时候依次更新rank[]

	fa[a]=b;
	rank[a]=(rank[x]+rank[y]+1)%2;

}
int main()
{
	int cas;
	scanf("%d",&cas);
	while(cas--)
	{
		int m,a,b,i;
		char ch[3];
		scanf("%d%d",&n,&m);
        Init();
		for(i=1;i<=m;i++)
		{
			scanf("%s%d%d",ch,&a,&b);
			if(ch[0]=='D')
			{
				Union(a,b);
			}
			else
			{
				if(n==2)printf("In different gangs.\n");
				else if(find(a)==find(b))
				{
					if(rank[a]==rank[b])
						printf("In the same gang.\n");
					else
						printf("In different gangs.\n");

				}
				else
					printf("Not sure yet.\n");
			}

		}

	}
	return 0;

}
poj1182

题目大意:

食物链 关系有三种情况 rank[] 表示与父亲的关系 0 同类 1 吃父亲,2 被父亲吃

关于向量的问题,这里有牛人很好的说明。O(∩_∩)O哈哈~ 我也是站在巨巨的肩膀上\(^o^)/~

http://www.cnblogs.com/wuyiqi/archive/2011/08/24/come__in.html

另外这个题还WA了好多次,其一是要单组数据才能过,其二就是合并的时候父节点写反辣。。噗噗。。

//食物链 关系有三种情况 rank[] 表示与父亲的关系 0 同类 1 吃父亲,2 被父亲吃
// 应该是和上一道提一样的 但总觉得有些不明白的地方
//好多牛人啊。。向量 tx ty 分别为x y 与其的父亲的关系,已知 x->tx x->y y->ty
// 求 tx->ty 因为两个合并时要fa[ty]=tx;
// tx->ty = tx->x+x->y+y->ty
// so:tx->ty=(-rank[x]+d-1+rank[y])%3;=(rank[y]-rank[x]+d-1)%3

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int n;
int fa[55555];
int rank[55555];

void Init()
{
    for(int i=1;i<=n;i++)
    {
        fa[i]=i;
        rank[i]=0;
    }
}

int find(int x)
{
    if(fa[x]!=x)
    {
        int fath=find(fa[x]);
        rank[x]=(rank[x]+rank[fa[x]])%3;
        return fa[x]=fath; // 路径压缩 的时候rank[]如何修改呢?
                    // fa[x]=ffa[x] x->tx tx->ttx so:x->ttx=(rank[x]+rank[fa[x]])%3;
    }
    return x;
} 

int Union(int d,int x,int y)
{
	if(x>n || y>n)return 1;	
    if(d==1 && x==y)return 1; 
    int tx=find(x);
    int ty=find(y);
    if(tx==ty)
    {
        if((rank[y]-rank[x]+3)%3!=d){return 1; }
        else return 0;
    }
    else
    {
        fa[ty]=tx; //这里不能写反了。。。 
        rank[ty]=(rank[x]-rank[y]+d+3)%3;
        return 0;
    }
}

int main()
{
//	freopen("q.in","r",stdin);
    int k,d,x,y,res,i;
    scanf("%d%d",&n,&k)==2;
    res=0;
    Init();
    for( i=1;i<=k;i++)
    {
        scanf("%d%d%d",&d,&x,&y);
        if(Union(d-1,x,y))res++;
    }
    cout<<res<<endl;
    	
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: