P1955 [NOI2015] 程式自動分析題解
阿新 • • 發佈:2021-08-09
一、基本版本
上來一看,這就是一個簡單的並查集:
(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億左右