若一 n 點簡單圖的度數序列為
如果直接套入定理算 k 從 1 跑到 n,時間複雜度會是
故整體時間複雜度為 O(n)。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
bool ErdosGallai(const vector<int> °) {
ll LHS = 0, RHS, N = deg.size(), suffix = 0;
ll pos = N; // suffix = deg[pos] + ... deg[N-1]
for (int k = 1; k <= N; ++k) {
LHS += deg[k - 1];
RHS = k * (k - 1LL);
// 由後往前加,在算公式的右手邊加總 for min(di, k) = di
// 每回合 pos 最多只減一次
while (pos - 1 >= k && deg[pos - 1] < k) {
suffix += deg[pos - 1];
pos--;
}
// 公式左手邊,因為 pos 的位置比 k 還要前面了,所以要將之前多加的項要扣除
// 每回合 pos 最多只加一次,因為 pos 和 k 最多差 1
while (pos < k) {
suffix -= deg[pos];
pos++;
}
RHS += suffix;
// min(di, k) = k,因為是由大到小排序所以可以一次處理 deg 超過 k 的部分
if (pos > k) RHS += (pos - k) * k;
if (LHS > RHS) return false;
}
return true;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
// cnt 計算度數頻率,Counting Sort 要用
vector<int> deg, cnt;
int N;
while (cin >> N, N) {
deg.clear();
deg.reserve(N);
cnt.assign(N, 0);
ll sum = 0;
int mx = 0;
bool isSimple = true;
for (int i = 0; i < N; ++i) {
int tmp;
cin >> tmp;
sum += tmp; // 計算左邊項 d1 + ... + di
mx = max(mx, tmp); // 最大值拿來判斷用
// 合法度數範圍 0 ~ N-1
if (0 <= tmp && tmp < N) cnt[tmp]++;
else {
isSimple = false;
break;
}
}
if ((sum % 2 != 0) || (mx >= N)) isSimple = false;
if(isSimple){
// counting sort
for (int i = N - 1; i >= 0; --i) {
while (cnt[i]--)
deg.emplace_back(i);
// push 進去的意思,但效率比 push_back() 好
}
if (!ErdosGallai(deg)) isSimple = false;
}
if (isSimple) cout << "Possible\n";
else cout << "Not possible\n";
}
}
有時間再寫