1. 程式人生 > 其它 >P1955 [NOI2015] 程式自動分析題解

P1955 [NOI2015] 程式自動分析題解

題目傳送門

一、基本版本

上來一看,這就是一個簡單的並查集:
(1)如果說兩個數字相等,那麼就合併為同一家族。
(2)如果說兩個數字不等,就檢查以前它們是不是同一家族的,如果是,就是說明出現了矛盾,直接輸入NO,退出即可。

但現實很殘酷,一道綠題哪能是這麼容易過的,只能通過第一個測試點:

#include <bits/stdc++.h>

using namespace std;

int t;//表示需要判定的問題個數
int n;//表示該問題中需要被滿足的約束條件個數
int x; //第一個數
int y; //第二個數
int e; //是否相等,1相等,0不相等

const int N = 1e6 + 10;
int fa[N];

//要深入理解這個遞歸併壓縮的過程
int find(int x) {
    if (fa[x] != x) fa[x] = find(fa[x]);
    return fa[x];
}

//加入家族集合中
void join(int c1, int c2) {
    int f1 = find(c1), f2 = find(c2);
    if (f1 != f2)fa[f1] = f2;
}

int main() {
    cin >> t;
    while (t--) {
        cin >> n;
        //初始化並查集
        for (int i = 1; i < N; i++) fa[i] = i;

        bool success = true;
        for (int i = 1; i <= n; i++) {
            cin >> x >> y >> e;
            //現在說兩個數相等,描述為同一個家族
            if (e == 1) join(x, y);
            else {
                //現在說兩個數不等,那麼檢查一下,以前記錄下來的是不是不等,即不是同一個家族,如果發現矛盾,就退出
                if (find(x) == find(y)) {
                    success = false;
                    break;
                }
            };
        }
        if (success) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}

二、離散化

為什麼會出現上面的情況呢?其實我們忽略了一個最基本的常知:OI中,必須關注資料範圍~~

看到了沒,這\(i,j\)都是上限\(1e9\)啊,我們開的陣列\(fa[N]\),它能表示的範圍是\(1e6+10\),太小了,不死才怪!
那我們把\(N\)擴大到 \(1e9+10\)是不是就可以了呢??

當然不行了,要不還能叫綠題!!NOIP中,有如下的規則上限:
空間上限128MB

\(int = 4\)位元組
\(char = 1\)位元組
\(long long = 8\)位元組
\(128M = 128 *1024k= 131072KB = 134217728\)位元組

結論:
$int$型一維陣列最多是3千萬
$long\ long$型一維陣列最多是1千5百萬
$char$型一維陣列最多是1億左右