POJ 1659 青蛙的邻居们

次元传送门

题意:
不用老朽说了,此题中文…….

分析:
请学习Havel Hakimi算法,不然…. 暴搜吧,走好不送
送上两个链接
万能的度娘百科
无敌的维基百科
去看看吧,不讲了

还是来补一下Havel定理吧
Havel定理是干嘛使的呢?是用来判断一个序列是否可图的。
什么是可图序列呢?就是把这个序列中的每个数字分别作为一张图上的每个点的临点数量(入度和出度,这是一个无向图),如果能构成这样一个图,就称序列是可图的,反之就称其不可图。
那么,我们来学习下Havel Hakimi定理吧!
首先,如果这个序列的和是一个奇数,那很明显它是不可图的,这是显然的。
其次,序列中的偶数不会对可图性产生任何影响,你甚至可以直接认为它们都形成了若干自环(虽然有些题中这种情况并不允许出现,例如此题,一只青蛙没法和他自己成为邻居,这是显然的)。
最后,我们来看看Havel定理是如何处理剩下的这些数的。
Havel定理的方法是先把他们都按从大到小排序一边,然后取出第一个数,开始想办法构造这个点的所有临边,方法是把这个点和他后面的a个点分别连一条边,a就是这个数。注意连边的时候直接把连向的点的临边数 – (自减)。
不断重复以上过程,直到序列中的所有数字都变为0,代表此序列是可图的,且当前建出来的图就是一个解。
如果在以上过程中出现了-1(负数),那就说明当前序列是不可图的。
注意,每次都应对序列排序,大的在前,0在最后。
注意,数字要跟着输入时的编号一起跑,这样才能按照编号见图,否则你的程序只能判断是否可图。代码实现多种多样,我只是不想写结构体了,用个pair还是蛮方便的。

那么,代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=10+5;
inline bool cmp(pair<int,int> a,pair<int,int> b){
  return a.first>b.first;
}
int main(){
  int c,n,sum;
  cin>>c;
  pair<int,int> p[maxn];
  int ans[maxn][maxn];
  while(c--){
    memset(ans,0,sizeof(ans));
    sum=0;
    cin>>n;
    for(int i=0,w;i<n;i++){
      cin>>w;
      p[i]=make_pair<int,int>(w,i);
      sum+=w;
    }
    if(sum&1){
      cout<<"NO"<<endl<<endl;
      continue;
    }
    bool flag=false;
    for(int i=0;i<n;i++){
      sort(p+i,p+n,cmp);
      for(int j=1;j<=p[i].first;j++){
        p[i+j].first--;
        if(p[i+j].first==-1){
          flag=true;
          break;
        }
        ans[p[i].second][p[i+j].second]=ans[p[i+j].second][p[i].second]=1;
      }
      if(flag)  break;
    }
    if(flag){
      cout<<"NO"<<endl<<endl;
      continue;
    }
    cout<<"YES"<<endl;
    for(int i=0;i<n;i++,cout<<endl)
      for(int j=0;j<n;j++)
        cout<<ans[i][j]<<" ";
    cout<<endl;
  }
  return 0;
}

By YOUSIKI

你可能感兴趣的:(POJ 1659 青蛙的邻居们)