题意:我们常根据无向边来计算每个节点的度,现在反过来了,已知每个节点的度,问是否可图,若可图,输出一种情况。
分析:这是一道定理题,只要知道可图定理,就是so easy了
可图定理:对每个节点的度从大到小排序,取第一个(最大)的度的节点,依次与其后(度)的节点连边,每连一条边,对应的度减1。然后重新排序,重复以上步骤,若度出现负值,则不可图。(若n个点中,某点的度>=n,那么也是不可能的)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 const int MAXN=22; 7 8 int a[MAXN],r[MAXN]; 9 int mp[MAXN][MAXN]; 10 11 void init(int n) 12 { 13 memset(a,0,sizeof(a)); 14 memset(mp,0,sizeof(mp)); 15 for(int i=0;i<n;i++) 16 r[i]=i; 17 } 18 19 int cmp(int i,int j) 20 { 21 return a[i]>a[j]; 22 } 23 24 int check(int n) 25 { 26 for(int i=0;i<n;i++) 27 { 28 for(int j=1;j<1+a[r[0]];j++) 29 { 30 mp[r[0]][r[j]]=mp[r[j]][r[0]]=1; 31 a[r[j]]--; 32 if(a[r[j]]<0) 33 return -1; 34 } 35 a[r[0]]=0; 36 sort(r,r+n,cmp); 37 } 38 return 1; 39 } 40 41 void print(int n) 42 { 43 for(int i=0;i<n;i++) 44 { 45 for(int j=0;j<n;j++) 46 if(j==0) 47 printf("%d",mp[i][j]); 48 else 49 printf(" %d",mp[i][j]); 50 printf(" "); 51 } 52 } 53 54 int main() 55 { 56 int T,n; 57 scanf("%d",&T); 58 while(T--) 59 { 60 scanf("%d",&n); 61 init(n); 62 for(int i=0;i<n;i++) 63 scanf("%d",&a[i]); 64 sort(r,r+n,cmp); 65 66 if(check(n)==-1) 67 printf("NO "); 68 else { 69 printf("YES "); 70 print(n); 71 } 72 printf(" "); 73 } 74 return 0; 75 }