您的位置:首页 > 其它

POJ 1659 Frogs' Neighborhood(Havel方法)

2014-05-18 23:56 501 查看
说的复杂了是Havel方法, 实际上能通过分析找出规律

目给出n个池塘, 告诉每个池塘相邻池塘的个数, 问是否存在一种池塘的分布符合题目的要求

显然应该先处理最多的, 因为它与大部分池塘发生联系, 假设池塘i相邻的池塘有xi个, 则处理完池塘i之后, 有另外xi个池塘的相邻池塘数xj会减小1.

为了保证相邻池塘数多的池塘都能符合要求, 应该从池塘数多的池塘进行减1操作

另外给出Havel方法的证明

给定一个非负整数序列{dn},若存在一个无向图使得图中各点的度与此序列一一对应,则称此序

列可图化。进一步,若图为简单图,则称此序列可简单图化   

可图化的判定:d1+d2+……dn=0(mod 2)。关于具体图的构造,我们可以简单地把奇数度的点配

对,剩下的全部搞成自环。  

可简单图化的判定(Havel定理):把序列排成不增序,即d1>=d2>=……>=dn,则d可简单图化当且仅当

d’={d2-1,d3-1,……d(d1+1)-1, d(d1+2),d(d1+3),……dn}可简单图化。简单的说,把d排序后,

找出度最大的点(设度为d1),把它与度次大的d1个点之间连边,然后这个点就可以不管了,一直继续这

个过程,直到建出完整的图,或出现负度等明显不合理的情况。

对于一个给定的度序列,看能不能形成一个简单无向图。

Havel算法的思想简单的说如下:

(1)对序列从大到小进行排序。

(2)设最大的度数为 t ,把最大的度数置0,然后把最大度数后(不包括自己)的t 个度数分别减1

(意思就是把度数最大的点与后几个点进行连接)

(3)如果序列中出现了负数,证明无法构成。如果序列全部变为0,证明能构成,跳出循环。前两

点不出现,就跳回第一步!

举例说明:

4 4 3 3 2 2

第二步后0 3 2 2 1 2

排完续后3 2 2 2 1 0

第二步后0 1 1 1 1 0

排完续后1 1 1 1 0 0

第二步后0 0 1 1 0 0

排完续后1 1 0 0 0 0

第二步后0 0 0 0 0 0

全为0,能构成图,跳出!

2 1 1 1

第二步后0 0 0 1

排完续后1 0 0 0

第二步后0 -1 0 0

出现负数,直接退出!

#include <iostream>
#include <cstring>
#include <fstream>
#include <algorithm>
using namespace std;
struct Node
{
int xu, num;
} q[12];
int g[12][12];
int cmp(Node a, Node b)
{
return a.num > b.num;
}
int main()
{
int t, i, j, n, flag;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
flag = 0;
for(i = 1; i <= n; i++)
{
scanf("%d", &q[i].num);
q[i].xu = i;
}
memset(g, 0, sizeof(g));
while(1)
{
sort(q+1, q+n+1, cmp);
if(q[1].num == 0)
break;
for(i = 1; i <= q[1].num; i++)
{
q[1+i].num--;
g[q[1].xu][q[1+i].xu] = g[q[1+i].xu][q[1].xu] = 1;
if(q[1+i].num < 0)
{
flag = 1;
break;
}
}
if(flag == 1)
break;
q[1].num = 0;
}
if(flag)
printf("NO\n");
else
{
printf("YES\n");
for(i=1; i<=n; i++)
for(j=1; j<=n; j++)
printf("%d%c",g[i][j],j==n?'\n':' ');
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: