概念:
给出一个无向图的顶点度序列{dn},要求判断能否构造出一个简单无向图。
Havel定理:
基于贪心。
每次把顶点按度大小从大到小排序,取出度最大的点Vi,依次和度较大的那些顶点Vj连接,同时减去Vj的度。
连接完之后就不再考虑Vi了(排序的时候可以直接从du[k]开始排;把这一点的度置零,为零了应该也没有影响了吧,因为如果对零减直接就跳出循环了,可判定不能成图),剩下的点再次排序然后找度最大的去连接……这样就可以构造出一个可行解。
判断无解条件:
<1> 若某次选出的Vi的度比剩下的顶点还多,则无解;(注意不要数组越界)
<2> 若某次Vj的度减成了负数,则无解。
模版:(POJ1659 Frogs' Neighborhood)
(我不懂为什么我用puts(“ ”)会WA。。。)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=13;
int ans[maxn][maxn];
int t,n;
struct p
{
int ind,dunum;
}du[maxn];
bool operator<(const p &a,const p &b){
return a.dunum>b.dunum;
}
int main()
{
//freopen("in","r",stdin);
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(du,0,sizeof(du));
memset(ans,0,sizeof(ans));
int i,j,k;
for(i=0;i<n;i++)
{
scanf("%d",&du[i].dunum);
du[i].ind=i;
}
sort(du,du+n);//printf("%d ",du[n-1].dunum);
bool f=true;
//for(i=0;i<n;i++)
//printf("id = %d , dunum= %d\n",du[i].ind,du[i].dunum);
for(k=0;k<n;k++)
{
sort(du+k,du+n);
if(du[k].dunum>n-k-1)
{
f=false;
break;
}
for(j=1;j<=du[k].dunum;j++)
{
du[k+j].dunum--;
if(du[k+j].dunum<0)
{
f=false;
break;
}
ans[du[k].ind][du[k+j].ind]=1;
ans[du[k+j].ind][du[k].ind]=1;
}
}
// for(i=0;i<n;i++)
//printf("id = %d , dunum= %d\n",du[i].ind,du[i].dunum);puts("");
if(f)
{
printf("YES\n");
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
printf("%d ",ans[i][j]);
}
printf("\n");
}
}
else
printf("NO\n");
printf("\n");
}
return 0;
}另一种写法:(自己写的)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=13;
int ans[maxn][maxn];
int t,n;
struct p
{
int ind,dunum;
bool operator < (const p &rhs) const{
return dunum > rhs.dunum;
}
}du[maxn];
int main()
{
//freopen("in","r",stdin);
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(du,0,sizeof(du));
memset(ans,0,sizeof(ans));
int i,j;
for(i=0;i<n;i++)
{
scanf("%d",&du[i].dunum);
du[i].ind=i;
}
sort(du,du+n);//printf("%d ",du[n-1].dunum);
bool f=true;
// for(i=0;i<n;i++)
//printf("id = %d , dunum= %d\n",du[i].ind,du[i].dunum);
while(du[0].dunum>0&&f)
{
if(du[0].dunum<n)
{
for(i=1;i<=du[0].dunum;i++)
{
du[i].dunum--;
if(du[i].dunum<0)
{
f=false;
break;
}
// cout<<i<<endl;
//printf("du[%d] . dunum= %d\n",i,du[i].dunum);
ans[du[0].ind][du[i].ind]=1;
ans[du[i].ind][du[0].ind]=1;
}
}
else
{
f=false;
break;
}
du[0].dunum=0;
sort(du,du+n);
//for(i=0;i<n;i++)
//printf("id = %d , dunum= %d\n",du[i].ind,du[i].dunum);puts("");
}
if(du[n-1].dunum==0&&du[0].dunum==0&&f)
{
printf("YES\n");
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
printf("%d ",ans[i][j]);
}
printf("\n");
}
}
else
printf("NO\n");
printf("\n");
}
return 0;
}
本文介绍如何利用Havel定理判断给定的顶点度序列是否能构成简单无向图,并通过两种不同的实现方式展示算法的具体步骤。该算法采用贪心策略,通过不断连接度数最大的顶点来构造图。
1305

被折叠的 条评论
为什么被折叠?



