老师说是阿基米定律的题,根据每个点的度数判断这些点能不能构成图。
实则用起来我认为是一种贪心的思想,举个栗子:(首先不可能有点的度数为负
(1)各个点的度数 4 3 1 5 4 2 1 (每次都从大到小排序)
5 4 4 3 2 1 1,先解决度数最多的点他有5个邻居(是邻居,那度数-1),当然是优先考虑他后面的5个,因为是相较而言邻居(度数)比较多的,如果先考虑度数少的,那它的度数很快为负,显然不合理
3 3 2 1 1 0 -> 2 1 1 0 0 -> 0 0 0 0 最后变成了一个全是0的序列,说明各个点的度数恰好匹配,能构成一个所给序列度数的图。
(2)各个点的度数 4 3 1 4 2 0
4 4 3 2 1 0 -> 3 2 1 0 0 ->1 0 -1 0 出现一个点a的度数为负数了,说明这个图肯定构成不了了,因为是从大到小排序的,所以最大的点选择和a或a后面的点当邻居,都会使其度数为负
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int T,N;
struct S{
int id;
int num;
}f[1000];
int tt[20][20];
bool cmp(S a,S b){
return a.num>b.num;
}
bool solve(){
for(int i=1;i<=N;++i){
sort(f+i,f+1+N,cmp);//每次去掉一个最大的排序
int num=f[i].num;//最大的那个数
for(int j=i+1;j<=i+num;++j){//在这个数后面的num位都-1,减去一个度
tt[f[i].id][f[j].id]=1;//标记一下他们是联通的
tt[f[j].id][f[i].id]=1;
f[j].num--;//度数-1
if(f[j].num<0){//如果度数<0了,则说明这个图不能联通了,因为度数不可能为负数
return 0;
}
}
}
return 1;
}
int main(){
scanf("%d",&T);
while(T--){
memset(tt,0,sizeof(tt));
scanf("%d",&N);
for(int i=1;i<=N;++i){
cin>>f[i].num;
f[i].id=i;
}
if(solve()){
cout<<"YES"<<endl;
for(int i=1;i<=N;++i){
for(int j=1;j<=N;++j){
cout<<tt[i][j]<<' ';
}
cout<<endl;
}
}
else cout<<"NO"<<endl;
cout<<endl;
}
return 0;
}