URAL1003 Parity

本文介绍了一种利用并查集与Hash技术解决数值冲突的方法,通过具体实例讲解了如何实现路径压缩以提高效率,并展示了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个题应该思路蛮多的,,,,,一个比较成熟的思路就是用并查集,,,其实不是很好想到我觉得(事实上很像线段树什么的好吧),,,,就是 1 2 odd就看成sum(2)-sum(0)为odd,放在一起,然后相减为even的放在一起,,,之后要是有矛盾的(二合一)就错了,,,,,,这题到这里其实就是一个模板题嘛。。。。。敲敲并查集路径压缩下就好,,,只是数据量大内存不够。。。。所以要用到HASH(现学现卖。。。)哎,,,,,,,就说这么多了,,,别的也没啥,,顺便复习一下并查集。。。。。。。


先讲一下hash:

把一个值映射到特定的key上,(通过一个固定的算法函数),一般是变成一个数,,,,知道了这个数,也就知道了在原来的位置;

并查集:

原理很好懂,代码还是模板,注意一下路径压缩就好,,主要就是两个点连线,一个新来的找到以前的人的大哥并与之连线,大家就是手拉手的亲兄弟了,两边拉一起了就错了矛盾了。。。。。。


贴代码写注释。。。。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

int hash1[11111];
int pre[22222];
int m,n;


void chushihua()     //并查集的初始化,,,之前每个人都只有自己这么一个兄弟。。。。。
{
    for(int i=0;i<22222;i++) pre[i]=i;
}

int find(int x)       //查找是哪个圈子的,,,,一直往上找,,,如果大哥不是它本身的话,,就去找他的大哥,,直到拜人家最大的大哥为大哥
{
    int r=x;
    while ( pre[r ] != r )
          r=pre[r ];
    int i=x , j ;
    while( i != r )         //这个就是路径压缩了,,所有人都是一个人的小弟,,,没有小弟的小弟了
    {
         j = pre[ i ];
         pre[ i ]= r ;
         i=j;
    }
    return r ;
}

void join(int x,int y)    //加入帮会,,,,,要是俩人的大哥不一样,,,就合并一下
{
    int fx=find(x),fy=find(y);
    if(fx!=fy)
        pre[fx]=fy;
}

int hahahash(int x)
{
    int key=x%11111;
    while(hash1[key]!=-1&&hash1[key]!=x) key=(key+10)%11111;  //如果取余11111的有数字了,,那就加10再取余,,,,省空间嘛。。。。
    if(hash1[key]==-1) hash1[key]=x;
    return key;
}


int main()
{
    while(scanf("%d",&n)&&n!=-1)
    {
        chushihua();
        scanf("%d",&m);
        memset(hash1,-1,sizeof(hash1));
        int a,b;
        int ans=-1;
        char s[10];
        int i;
        for(i=0;i<m;i++)
        {
            scanf("%d%d%s",&a,&b,s);
            if(ans!=-1) continue;  //已经不对了,,剩下的就读取一下就拉倒了也别管别的了
            if(a>b) swap(a,b);
            a=hahahash(a-1);
            b=hahahash(b);
            if(strcmp(s,"even")==0)
            {
                if(find(a)==find(b+11111)||find(a+11111)==find(b))   //发现两个帮派合一起了
                    ans=i;
                join(a,b);      
                join(a+11111,b+11111);  //加的11111(maxn)就是相当于开了两个数组,,,,一个是同奇偶一个是不同奇偶的,,,,,,
            }
            else
            {
                if(find(a)==find(b)||find(a+11111)==find(b+11111))
                    ans=i;
                join(a+11111,b);
                join(b+11111,a);
            }
        }
        printf("%d\n",ans!=-1?ans:m);
    }
 return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值