1. 程式人生 > >【NOI2015】程序自動分析

【NOI2015】程序自動分析

單個 -- space != name style namespace cstring 說明

題目描述

在實現程序自動分析的過程中,常常需要判定一些約束條件是否能被同時滿足。

考慮一個約束滿足問題的簡化版本:假設x1,x2,x3...代表程序中出現的變量,給定n個形如xi=xj或xi≠xj的變量相等/不等的約束條件,請判定是否可以分別為每一個變量賦予恰當的值,使得上述所有約束條件同時被滿足。例如,一個問題中的約束條件為:x1=x2,x2=x3,x3=x4,x4≠x1,這些約束條件顯然是不可能同時被滿足的,因此這個問題應判定為不可被滿足。

現在給出一些約束滿足問題,請分別對它們進行判定。

輸入輸出格式

輸入格式:

從文件prog.in中讀入數據。

輸入文件的第1行包含1個正整數t,表示需要判定的問題個數。註意這些問題之間是相互獨立的。

對於每個問題,包含若幹行:

第1行包含1個正整數n,表示該問題中需要被滿足的約束條件個數。接下來n行,每行包括3個整數i,j,e,描述1個相等/不等的約束條件,相鄰整數之間用單個空格隔開。若e=1,則該約束條件為xi=xj;若?e=0,則該約束條件為xi≠xj;

輸出格式:

輸出到文件 prog.out 中。

輸出文件包括t行。

輸出文件的第 k行輸出一個字符串“ YES” 或者“ NO”(不包含引號,字母全部大寫),“ YES” 表示輸入中的第k個問題判定為可以被滿足,“ NO” 表示不可被滿足。

輸入輸出樣例

輸入樣例#1:
2
2
1 2 1
1 2 0
2
1 2 1
2 1 1
輸出樣例#1:
NO
YES

說明

【樣例解釋1】

在第一個問題中,約束條件為:x1=x2,x1≠x2。這兩個約束條件互相矛盾,因此不可被同時滿足。

在第二個問題中,約束條件為:x1=x2,x1=x2。這兩個約束條件是等價的,可以被同時滿足。

【樣例說明2】

在第一個問題中,約束條件有三個:x1=x2,x2=x3,x3=x1。只需賦值使得x1=x1=x1,即可同時滿足所有的約束條件。

在第二個問題中,約束條件有四個:x1=x2,x2=x3,x3=x4,x4≠x1。由前三個約束條件可以推出x1=x2=x3=x4,然而最後一個約束條件卻要求x1≠x4,因此不可被滿足。

【數據範圍】

技術分享

【時限2s,內存512M】

題解

並查集+離散化。

先執行所有x=y問題,合並x和y。

再依次執行所有x!=y問題,即查詢x和y是否處於同一集合。如果是,則有x=y且x!=y,不滿足條件。

如果所有的x!=y都得到滿足,這組數據就可以滿足。

註意到i,j範圍為[1,1e9],parent數組開不了這麽大的範圍。又註意到n範圍只有[1,1e5],考慮離散化。

先讀入所有出現的數字,存到一個數組,然後排序並去重。之後操作用到的數字都在這個數組進行二分查找。

時間復雜度O(nlogn)。

註意的坑:

1、最多有n個操作,每個操作有兩個數字,所以並查集的大小應該是n*2。

2、我寫的時候二分查找返回的位置是從0開始的,並查集又寫成從1開始,就WA了一個點,調了好久才發現問題。

#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#define maxn 100005 * 2
using namespace std;
typedef unsigned long long ullint;
namespace djs
{
int parent[maxn];
inline void init()
{
    for (int i = 0; i < maxn; i++)
        parent[i] = -1;
}
inline int find(int x)
{
    int ance = x;
    while (parent[ance] >= 0)
        ance = parent[ance];

    int at = x;
    while (parent[at] >= 0)
    {
        int fa = parent[at];
        parent[at] = ance;
        at = fa;
    }

    return ance;
}
inline void merge(int x, int y)
{
    x = find(x);
    y = find(y);
    if (x == y)
        return;
    else
    {
        //令x為rank更大的,即parent值更小的
        if (parent[x] > parent[y])
            swap(x, y);
        parent[x] += parent[y];
        parent[y] = x;
    }
}
inline bool is_related(int x, int y)
{
    return find(x) == find(y);
}
}
typedef pair<ullint, ullint> query;
vector<query> q, m;                  //暫存查詢、合並操作
vector<ullint> data;                 //存儲讀入的所有數據
vector<ullint>::iterator unique_end; //去重後的數據的尾後叠代器
inline int get_pos(ullint v)         //二分查找v在data所處的位置
{
    return lower_bound(data.begin(), unique_end, v) - data.begin();
}
int main()
{
    ios::sync_with_stdio(false);
    int t;
    cin >> t;
    while (t--)
    {
        using namespace djs;

        int n;
        cin >> n;
        init();
        m.clear();
        q.clear();
        data.clear();

        ullint a, b, c;
        for (int i = 0; i < n; i++)
        {
            cin >> a >> b >> c;
            data.push_back(a);
            data.push_back(b);
            switch (c)
            {
            case 1:
                m.push_back(make_pair(a, b));
                break;

            case 0:
                q.push_back(make_pair(a, b));
                break;
            }
        }

        //離散化
        sort(data.begin(), data.end());
        unique_end = unique(data.begin(), data.end());

        //合並
        for (int i = 0; i < m.size(); i++)
            merge(get_pos(m[i].first), get_pos(m[i].second));

        //查詢
        bool yes = true;
        for (int i = 0; i < q.size(); i++)
        {
            if (is_related(get_pos(q[i].first), get_pos(q[i].second)))
            {
                yes = false;
                break;
            }
        }
        if (yes)
            cout << "YES" << endl;
        else
            cout << "NO" << endl;
    }
    return 0;
}

【NOI2015】程序自動分析