「NOI2015」程序自动分析

发布于 2018-01-08  262 次阅读


题目描述

题目描述

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

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

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

输入输出格式

输入格式

从文件 frog.in中读入数据。

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

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

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

输出格式

输出到文件 frog.out 中。

输出文件包括t行。

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

输入输出样例

输入样例

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

输出样例

NO
YES

题目分析

这一题可以用并查集做。我们将$ i,j $ 离散化后,如果相等,就合并这两个集合,如果不相等,就判断他们是否在一个集合内。当找到不符合前面条件的条件是,输出即可
用到的算法是 并查集离散化

样例代码

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

using namespace std;

const int MAXN = 600000 + 5;

#define LL long long
#define Data pair<LL,LL>

int f[MAXN],n;
Data a[MAXN];
int A[MAXN],B[MAXN],e[MAXN];

void init(){
    for(int i = 1;i <= 500010;i++)
        f[i] = i;
    memset(e,0,sizeof(e));
    memset(A,0,sizeof(A));
    memset(a,0,sizeof(a));
}

int find(int x){
    if(x == f[x])
        return x;
    return f[x] = find(f[x]);
}

void Union(int x,int y){
    f[find(x)] = find(y);
}

bool pd(int x,int y){
    return (find(x) == find(y));
}

bool cmp(Data x,Data y){
    return (x.first > y.first);
}

void lisan(Data a[],int A[]){
    int tot = 0;
    sort(a + 1,a + n*2 + 1,cmp);
    for (int i = 1;i <= n*2;i++)
    {
        if (i==1 || a[i].first != a[i-1].first) tot++;
        A[a[i].second] = tot;
    }
}

void work(){
    scanf("%d",&n);
        bool flag=0;
        init();
        for (int i=1;i<=n;i++)
        {
            LL aa,bb;
            scanf("%lld%lld%d",&aa,&bb,&e[i]);
            a[i] = make_pair(aa,i);
            a[i + n] = make_pair(bb,i+n);
        }
        lisan(a,A);
        for (int i=1;i<=n;i++) B[i]=A[n+i];
        for (int i=1;i<=n;i++)
            if (e[i]) Union(A[i],B[i]);
        for (int i=1;i<=n;i++)
            if (!e[i])
                if (pd(A[i],B[i])){
                    flag=1;break;
                }
        if(!flag) printf("YES\n");
        else printf("NO\n");
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--) work();
  return 0;
}



一个OIer。