pku1733 Parity game(离散化+并查集拓展应用)

这题目让我郁闷了好久的说,首先就是离散化过程,区间大小和测试的例子相差太大,十分有必要进行离散化,这里就出现一个问题了,这道题目而已,离散化过程需要保持数据之间的相对大小吗?需要跟不需要相差很多吗?差别的话,当然很大啦,如果不需要保持数据的相对大小,那么,在映射过程中就可以直接将映射值放入运算了,而如果需要呢?这时,我们需要先将读入的数据保存,再排序,进入hash,或者使用map函数,这一过程就用了好多内存了和时间了

为什么不需要保持数据的相对大小呢?因为我们用的是并查集,每个节点都有一个根节点,这里就是关键了,根节点是如何选的呢?呵呵,其实仔细想想,我们如何判断一个区间内1 的个数的奇偶性呢?利用的区间端点跟根节点的关系推出来,而这里,根节点具体是哪一个并不知道,这个要看输入数据了,这时我们发现,端点大小跟该区间内1的个数的奇偶性有关系吗?没关系对吧,我们记录的是,出现过的节点到根节点之间的1的个数的奇偶性

还有一道类似的题目,也贴出了吧,hdu3038

#include<stdio.h>
#define MAXN 200010
int f[MAXN],r[MAXN];
int find(int x)
{
	if(x==f[x])
		return f[x];
	int t=find(f[x]);
	r[x]=r[x]+r[f[x]];
	f[x]=t;
	return f[x];
}
int fun(int x,int y)
{
	if(x>y)
		return x-y;
	else y-x;
}
int Union(int x,int y,int sum)
{
	int a=find(x);
	int b=find(y);
	if(a==b)
	{
		if(fun(r[x],r[y])==sum)
			return 0;
		else return 1;
	}
	else 
	{
		f[a]=b;
		r[a]=r[y]+sum-r[x];
		return 0;
	}
}
int main()
{
	int n,m,i,ans,a,b,s;
	while(scanf("%d %d",&n,&m)!=EOF)
	{
		ans=0;
		for(i=0;i<=n;i++)
		{
			f[i]=i;
			r[i]=0;
		}
		for(i=1;i<=m;i++)
		{
			scanf("%d %d %d",&a,&b,&s);
			a--;
			if(Union(a,b,s))
				ans++;
		}
		printf("%d\n",ans);
	}
	return 0;
}
pku1733
#include<iostream>
#include<map>
#include<stdio.h>
using namespace std;
#define MAXN 10010
int f[MAXN],r[MAXN];
//f[]记录父节点,r[]记录与根节点直接1的奇偶性
void init()
{
	int i;
	for(i=0;i<=10001;i++)
	{
		f[i]=i;
		r[i]=0;
	}
}//还是老步骤,初始化并查集
int find(int x)
{
	if(f[x]==x)
		return x;
	int t=find(f[x]);
	r[x]=(r[x]+r[f[x]])%2;//这里的话,别当成什么公式吧,可以这样 想,根据当前节点与父节点的关系,以及父节点与根节点的关系,推出当前节点与根节点的关系
	f[x]=t;
	return f[x];
}//压缩路径
int Union(int x,int y,int d)
{
	int a=find(x);
	int b=find(y);
	if(a==b)
	{
		if((r[x]+r[y])%2==d)//这个也好理解吧,并查集做了这么多了
			return 1;
		else return 0;
	}
	else {
		f[a]=b;
		r[a]=(r[x]+r[y]+d)%2;//这一步的话,涉及四个节点了,根据其他三个节点之间的关系,觉得第四个节点与根节点的关系
		//剩下的还是在压缩路径的过程中解决
		return 1;
	}
}
int main()
{
	int i,j,n,m,a,b,add=0;
	int x,y,d;
	char s[5];
	scanf("%d %d",&n,&m);
	init();
	map<int,int> mm;
	for(i=1;i<=m;i++)
	{
		scanf("%d %d %s",&a,&b,s);
		a--;
		if(mm.find(a)==mm.end())//判定a是否已经映射过了
		{
			mm[a]=add++;
		}
		x=mm[a];
		if(mm.find(b)==mm.end())
		{
			mm[b]=add++;
		}
		y=mm[b];
		if(s[0]=='o')
			d=1;
		else d=0;
		if(Union(x,y,d)==0)//其实,测试数据只有一个,所以发现矛盾即可立即退出了
			break;
	}
	printf("%d\n",i-1);
	return 0;
}

转载于:https://www.cnblogs.com/nanke/archive/2011/05/11/2043689.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值