您的位置:首页 > 其它

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

2011-05-11 21:46 429 查看
这题目让我郁闷了好久的说,首先就是离散化过程,区间大小和测试的例子相差太大,十分有必要进行离散化,这里就出现一个问题了,这道题目而已,离散化过程需要保持数据之间的相对大小吗?需要跟不需要相差很多吗?差别的话,当然很大啦,如果不需要保持数据的相对大小,那么,在映射过程中就可以直接将映射值放入运算了,而如果需要呢?这时,我们需要先将读入的数据保存,再排序,进入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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: