luogu1955 [NOI2015]程序自动分析

luogu1955 题 目 传 送 门 l u o g u 1955


题目描述

在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。

考虑一个约束满足问题的简化版本:假设 x1,x2,x3... x 1 , x 2 , x 3 . . . 代表程序中出现的变量,给定 n n 个形如xi=xj xixj x i ≠ x j 的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足。例如,一个问题中的约束条件为: x1=x2,x2=x3,x3=x4,x4x1 x 1 = x 2 , x 2 = x 3 , x 3 = x 4 , x 4 ≠ x 1 ,这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足。

现在给出一些约束满足问题,请分别对它们进行判定。

输入输出格式

输入格式:

输入文件的第1行包含1个正整数 t t ,表示需要判定的问题个数。注意这些问题之间是相互独立的。

对于每个问题,包含若干行:

第1行包含1个正整数n,表示该问题中需要被满足的约束条件个数。接下来 n n 行,每行包括3个整数i,j,e,描述1个相等/不等的约束条件,相邻整数之间用单个空格隔开。若 e=1 e = 1 ,则该约束条件为 xi=xj x i = x j ;若 e=0 e = 0 ,则该约束条件为 xixj x i ≠ x j

输出格式:

输出文件包括 t t 行。

输出文件的第k行输出一个字符串“YES” 或者“NO”(不包含引号,字母全部大写),“YES” 表示输入中的第 k k 个问题判定为可以被满足,“NO” 表示不可被满足。

输入输出样例

输入样例#1:

2
2
1 2 1
1 2 0
2
1 2 1
2 1 1

输出样例#1:

NO
YES

输入样例#2:

2
3
1 2 1
2 3 1
3 1 1
4
1 2 1
2 3 1
3 4 1
1 4 0

输出样例#2:

YES
NO

说明

【样例说明1】

在第一个问题中,约束条件为:x1=x2,x1x2。这两个约束条件互相矛盾,因此不可被同时满足。

在第二个问题中,约束条件为: x1=x2,x1=x2 x 1 = x 2 , x 1 = x 2 。这两个约束条件是等价的,可以被同时满足。

【样例说明2】

在第一个问题中,约束条件有三个: x1=x2,x2=x3,x3=x1 x 1 = x 2 , x 2 = x 3 , x 3 = x 1 。只需赋值使得x1=x1=x1,即可同时满足所有的约束条件。

在第二个问题中,约束条件有四个: x1=x2,x2=x3,x3=x4,x4x1 x 1 = x 2 , x 2 = x 3 , x 3 = x 4 , x 4 ≠ x 1 。由前三个约束条件可以推出 x1=x2=x3=x4 x 1 = x 2 = x 3 = x 4 ,然而最后一个约束条件却要求 x1x4 x 1 ≠ x 4 ,因此不可被满足。

【数据范围】

【时限2s,内存512M】


题解

这道题目可以写个程序自动分析
因为这道题目只有相等和不等这两种约束条件,所以我们可以分开判断。
因为”相等“约束之间没有约束,所以我们可以先做”相等“,再做”不等“。
我们将变量看成点,”相等“约束看成边,我们就可以构造一张无向图,其中,两个连通的点所对应的变量相等。
接着我们做”不等“的约束。若”不等“所约束的两个变量连通,则不可被满足。
所以,我们需要一个能够合并两个集合以及查询所在集合的数据结构,容易想到用并查集。
虽然 i,j109 i , j ≤ 10 9 ,但是最多只有 2n 2 n 个有用的变量,所以可以先离散化一下。
空间 O(N) O ( N ) ,时间 O(Nα(N)) O ( N α ( N ) )
其中 O(α(N)) O ( α ( N ) ) 为反阿克曼函数,当 N221019729 N ≤ 2 2 10 19729 时, α(N)<5 α ( N ) < 5 ,所以说,看作常数就好了。


总结

并查集的两个操作:合并两个集合以及查询所在集合,使得它能够维护一张无向图中节点的连通性。扩展一下,它还能够动态维护许多具有传递性的关系,如题中的”相等“约束。综上,需要维护无向图中节点连通性时,可以考虑并查集。


标程

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 50;
struct Ques{
    int u, v, w;
    Ques(int _u = 0, int _v = 0, int _w = 0)
    {
        u = _u; v = _v; w = _w;
    }
    bool operator <(const Ques &t) const
    {
        return w > t.w;
    }
}q[N];
int t, a[N], f[N];
int find(int x)
{
    return f[x] == x ? x : f[x] = find(f[x]);
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> t;
    for (int m, n; t--; )
    {
        cin >> m; n = 0;
        for (int i = 1; i <= m; i++)
        {
            cin >> q[i].u >> q[i].v >> q[i].w;
            a[++n] = q[i].u; a[++n] = q[i].v;
        }
        sort(q + 1, q + m + 1);
        sort(a + 1, a + n + 1);
        n = unique(a + 1, a + n + 1) - a - 1;
        for (int i = 1; i <= n; i++) f[i] = i;
        bool p = 1;
        for (int i = 1; i <= m && p; i++)
        {
            q[i].u = lower_bound(a + 1, a + n + 1, q[i].u) - a;
            q[i].v = lower_bound(a + 1, a + n + 1, q[i].v) - a;
            if (q[i].w) f[find(q[i].u)] = find(q[i].v);
            else if (find(q[i].u) == find(q[i].v)) p = 0;
        }
        puts(p ? "YES" : "NO");
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值