[题解] P1955 程序自动分析 (并查集+哈希表)

本文介绍如何使用并查集解决约束满足问题,通过哈希表映射处理大规模数据输入,确保算法效率。文章详细解释了算法思路,并提供了完整的代码实现。

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

  题意: 考虑一个约束满足问题:假设x1,x2,x3…代表程序中出现的变量,给定n个形如xi=xj或xi≠xj的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足。
  分析: 给出的约束条件一共有两种:
  1.xi=xj
  2.xi!=xj
  可以发现,对于每一种条件,他们之间是不会相互冲突的
  那么,不同时满足这两种条件,当且仅当一类条件全部满足时,另外一类条件至少有一条与前面相违背。
  这样,我们就可以将第一种约束条件放在一起,再一个个的去查询看是否第二种条件每个都满足
  具体用并查集实现即可
  那为啥要用HASH呢?
  注意看数据范围:1n1000001i,j1000,000,000
  直接用数组存的话肯定爆炸
  但是我们发现其实i,j的具体取值并没有什么卵用,所以我们直接把它映射到哈希表上用就可以了
  P.S:之前用的哈希函数老是挂,找了一下午没找出原因,结果把mod的值改了一下竟然A了?好吧,还是老老实实双函数吧!
  
  详细代码如下:
  

#include <bits/stdc++.h>
using namespace std;
const int mod=400003;
long long fa[mod],w1[100001],w2[100001],num[mod];
bool vis[mod];
int tot=0;
long long read() {
    long long ans=0,flag=1;
    char ch=getchar();
    while( (ch<'0' || ch>'9') && ch!='-' ) ch=getchar();
    if(ch=='-') flag=-1,ch=getchar();
    while(ch>='0' && ch<='9') ans=ans*10+ch-'0',ch=getchar();
    return ans*flag;
}
int find(int x) {
    if(x!=fa[x]) {
        fa[x]=find(fa[x]);
    }
    return fa[x];
}
void merge(int x,int y) {
    int fx=find(x),fy=find(y);
    if(fx!=fy) {
        fa[fx]=fy;
    }
    return ;
}
long long g(long long x) {
    return (x+463)%mod;
}
int main() {
    int t=read();
    long long a,b,c,x,y,m;
    while(t--) {
        tot=0;
        memset(vis,0,sizeof(vis));
        for(int i=0;i<mod;i++) fa[i]=i;
        m=read();
        for(long long i=1;i<=m;i++) {
            a=read(),b=read(),c=read();
            x=a%mod;y=b%mod;
            while(1) {
                if(!vis[x]) {
                    vis[x]=true;
                    num[x]=a;
                    break;
                }else if(num[x]==a) {
                    break;
                }else {
                    x=g(x);
                }
            }
            while(1){
                if(!vis[y]) {
                    vis[y]=true;
                    num[y]=b;
                    break;
                }else if(num[y]==b){
                    break;
                }else {
                    y=g(y);
                }
            }

            if(c) {
                merge(x,y);
            }else {
                tot++;
                w1[tot]=x;
                w2[tot]=y;
            }
        }

        bool flag=0;
        for(int i=1;i<=tot;i++) {
            if(find(w1[i])==find(w2[i])) {
                flag=1;
                break;
            }
        }
        if(flag) {
            printf("NO\n");
        }else {
            printf("YES\n");
        }
    }
    return 0;
} 

                                     by:Chlience

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值