POJ 1659(Havel-Hakimi定理)
利用Havel-Hakimi定理判断一个序列是否可图
Havel-Hakimi原路如下:
由非负整数组成的非增序列s:d1, d2, …, dn(n ≥ 2, d1 ≥ 1)
是可图的,当且仅当序列
s1: d2 – 1, d3 – 1, …, dd1+1 – 1, dd1+2, …, dn
是可图的。序列s1 中有n-1 个非负整数,s 序列中d1 后的前d1 个度数(即d2~dd1+1)减1 后构成
s1 中的前d1 个数。
例如,判断序列s: 7, 7, 4, 3, 3, 3, 2, 1 是否是可图的。删除序列s 的首项7,对其后的7 项每项
减1,得到:6, 3, 2, 2, 2, 1, 0。继续删除序列的首项6,对其后的6 项每项减1,得到:2, 1, 1, 1, 0,
-1,到这一步出现了负数。由于图中不可能存在负度数的顶点,因此该序列不是可图的。
再举一个例子,判断序列s: 5, 4, 3, 3, 2, 2, 2, 1, 1, 1 是否是可图的。删除序列s 的首项5,对其
后的5 项每项减1,得到:3, 2, 2, 1, 1, 2, 1, 1, 1,重新排序后为:3, 2, 2, 2, 1, 1, 1, 1, 1。继续删除序
列的首项3,对其后的3 项每项减1,得到:1, 1, 1, 1, 1, 1, 1, 1。如此再陆续得到序列:1, 1, 1, 1, 1,
1, 0;1, 1, 1, 1, 0, 0;1, 1, 0, 0, 0;0, 0, 0, 0。由此可判定该序列是可图的。
#include<stdio.h>
struct p
{
int v;
int x;
} a[22];
int main()
{
int i,j,l,k=1,n,m,s;
int tu[11][11];
int t;
scanf("%d",&t);
while(t--)
{
k=1;
memset(tu,0,sizeof(tu));
scanf("%d",&n);
for(i=1; i<=n; i++)
{
scanf("%d",&a[i].v);
a[i].x=i;
}
l=1;
while(l<=n)
{
s=0;
for(i=l; i<=n; i++)
for(j=i+1; j<=n; j++)
{
if(a[i].v<a[j].v)
{
m=a[i].v;
a[i].v=a[j].v;
a[j].v=m;
m=a[i].x;
a[i].x=a[j].x;
a[j].x=m;
}
}
for(i=l+1; i<=n; i++)
s+=a[i].v;
if(a[l].v>s)
{
k=0;
break;
}
for(i=l+1; i<=a[l].v+l; i++)
{
a[i].v--;
tu[a[l].x][a[i].x]=1;
tu[a[i].x][a[l].x]=1;
if(a[i].v<0)
{
k=0;
break;
}
}
if(k==0)
break;
l++;
}
if(k==0)
printf("NO\n\n");
else
{
printf("YES\n");
for(i=1; i<=n; i++)
{
for(j=1; j<=n; j++)
{
if(j==1)
printf("%d",tu[i][j]);
else
printf(" %d",tu[i][j]);
}
printf("\n");
}
printf("\n");
}
}
return 0;
}
利用Havel-Hakimi定理判断一个序列是否可图
Havel-Hakimi原路如下:
由非负整数组成的非增序列s:d1, d2, …, dn(n ≥ 2, d1 ≥ 1)
是可图的,当且仅当序列
s1: d2 – 1, d3 – 1, …, dd1+1 – 1, dd1+2, …, dn
是可图的。序列s1 中有n-1 个非负整数,s 序列中d1 后的前d1 个度数(即d2~dd1+1)减1 后构成
s1 中的前d1 个数。
例如,判断序列s: 7, 7, 4, 3, 3, 3, 2, 1 是否是可图的。删除序列s 的首项7,对其后的7 项每项
减1,得到:6, 3, 2, 2, 2, 1, 0。继续删除序列的首项6,对其后的6 项每项减1,得到:2, 1, 1, 1, 0,
-1,到这一步出现了负数。由于图中不可能存在负度数的顶点,因此该序列不是可图的。
再举一个例子,判断序列s: 5, 4, 3, 3, 2, 2, 2, 1, 1, 1 是否是可图的。删除序列s 的首项5,对其
后的5 项每项减1,得到:3, 2, 2, 1, 1, 2, 1, 1, 1,重新排序后为:3, 2, 2, 2, 1, 1, 1, 1, 1。继续删除序
列的首项3,对其后的3 项每项减1,得到:1, 1, 1, 1, 1, 1, 1, 1。如此再陆续得到序列:1, 1, 1, 1, 1,
1, 0;1, 1, 1, 1, 0, 0;1, 1, 0, 0, 0;0, 0, 0, 0。由此可判定该序列是可图的。
#include<stdio.h>
struct p
{
int v;
int x;
} a[22];
int main()
{
int i,j,l,k=1,n,m,s;
int tu[11][11];
int t;
scanf("%d",&t);
while(t--)
{
k=1;
memset(tu,0,sizeof(tu));
scanf("%d",&n);
for(i=1; i<=n; i++)
{
scanf("%d",&a[i].v);
a[i].x=i;
}
l=1;
while(l<=n)
{
s=0;
for(i=l; i<=n; i++)
for(j=i+1; j<=n; j++)
{
if(a[i].v<a[j].v)
{
m=a[i].v;
a[i].v=a[j].v;
a[j].v=m;
m=a[i].x;
a[i].x=a[j].x;
a[j].x=m;
}
}
for(i=l+1; i<=n; i++)
s+=a[i].v;
if(a[l].v>s)
{
k=0;
break;
}
for(i=l+1; i<=a[l].v+l; i++)
{
a[i].v--;
tu[a[l].x][a[i].x]=1;
tu[a[i].x][a[l].x]=1;
if(a[i].v<0)
{
k=0;
break;
}
}
if(k==0)
break;
l++;
}
if(k==0)
printf("NO\n\n");
else
{
printf("YES\n");
for(i=1; i<=n; i++)
{
for(j=1; j<=n; j++)
{
if(j==1)
printf("%d",tu[i][j]);
else
printf(" %d",tu[i][j]);
}
printf("\n");
}
printf("\n");
}
}
return 0;
}