source:
题意:这是2017中国大学生程序设计竞赛网络选拔赛的题1。首先题目给你一个求最小顶点覆盖的近似算法:每次取度数最大的点删去它和其关联的所有边,继续该过程直到完成覆盖。现要求构造一个图来“卡”这个算法,就是说要构造一个足够“坏”的图,使得按照题目该出的近似算法求出的顶点覆盖集的规模>=你能给出的顶点覆盖规模。输出构造的图和给出你的顶点覆盖。
思路:
看到此题时以为只用在演算纸上画出符合条件的图,然后程序直接输出,而事实证明并没这么简单,还是需要运用步骤性的算法解决。其实首先可以这样思考,假如我的顶点覆盖方案有n个点,那么要让近似算法选3*n个点,不妨直接构造成二分图,左边n个点,右边3n个点,现在目的便是连边使得近似算法取右边作为顶点覆盖即可。
连边的话倒着来想即可,右边取到最后只剩一个点(不妨设为n+1号点)时,要保证取n+1号点,那么该点至少连一条边到左边点集即可,这里要注意一点:留意近似算法是度数相同时取编号大的,所以预留的1~n号为自个儿方案的点就是这个目的。好继续倒推,对于n+2号点也只需连一条边到左边点集,不与刚刚n+1号点连的相同即可,依次类推一直到2n号点都只需连一条线,而对于2n+1号点,由于左边点集现在都已经度数为1了,所以2n+1号点至少要连两条边,这样这三个点都是度数为2,优先取2n+1满足条件,如此思路倒推回去....右边点集可以构造出来的点数:度数为1的有n个点,度数为2点的n/2,n/3,n/4.... n/k 求和只要大于3n即可
我取n=50大概算了一下,k=12即可。
代码如下:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
int n=50; //n为二分图左边的点数+3n为二分图右边点数
int tot=0,m=0,weight=1;
for(int i=n+1;i<=4*n;i++)
{
m+=weight;
tot+=weight;
if(tot+weight>n)
{
weight++;
tot=0;
}
}//以上统计边数m
printf("%d %d\n",4*n,m);
weight=1;
tot=0;
for(int i=n+1;i<=4*n;i++)
{
for(int j=tot+1;j<=tot+weight;j++)
{
printf("%d %d\n",j,i);
m++;
}
tot+=weight;
if(tot+weight>n)
{
weight++;
tot=0;
}
}
printf("%d\n",n);
for(int i=1;i<=n;i++) printf("%d\n",i);
return 0;
}
本文介绍了一种构造特殊图的方法,旨在挑战一种近似顶点覆盖算法。通过构建特殊的二分图,使该近似算法选取的顶点数量远超理想情况。文章详细阐述了构建思路与算法实现。
8066

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



