連結:https://tioj.ck.tp.edu.tw/problems/1210

題目大意

給定一個度序列,問這個度序列是否能構成一張簡單圖?

題解

最近恰好讀了圖論的書,若一個度序列可以構造出一個簡單圖,該序列又可稱為圖序列,利用度序列判定是否為簡單圖(無自環、重邊)在這本書【演算法觀點的圖論】第一章就有提到了,有兩個定理可以使用:

  1. Erdős–Gallai theorem

若度序列 d:d1d2dn 是圖序列 d 是偶數,且對於 1kn 都有

i=1kdik(k1)+j=k+1nmin{k,dj}
  1. Havel–Hakimi algorithm

對於 n2,若度序列 d:d1d2dn 是圖序列

d:d21,d31,,d1+d11,d2+d1,d2+d1,,dn

也是圖序列

可以發現第二個方法比較好實作,就是把度數最大的點,都接一條邊到度數較多的邊上。由於數字都是整數,可以利用 Counting Sort 或是一些技巧,就能在 O(V) 的時間判定是否為簡單圖了。

AC Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include<bits/stdc++.h>
using namespace std;

int c[10001];
int tmp[10001];
bool test(int mx)
{
memset(tmp,0,sizeof(tmp));
while( mx > 0 )
{
int req = mx, la = mx;
c[mx]--;
while(req>0&&la>0)
{
int del = min(c[la],req);
c[la]-=del;
tmp[la-1]+=del;
req-=del;
la--;
}
if( req ) return false;
while(la<=mx)
{
c[la]+=tmp[la];
tmp[la]=0;
la++;
}
while( !c[mx] ) mx--;
}
return true;
}

int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int N, tmp;

while(cin>>N,N)
{
int deg=0;
int mx=0;
memset(c,0,sizeof(c));
bool isSimple = true;

for(int i=0;i<N;++i)
{
cin>>tmp;
deg+=tmp;
mx=max(mx,tmp);
c[tmp]++;
}

if( deg%2!=0 ) isSimple = false;
else if( mx >= N ) isSimple = false;
else if( !test(mx) ) isSimple = false;

if( isSimple )cout<<"Yes\n";
else cout<<"No\n";
}
}