【HDU6150 2017中国大学生程序设计竞赛 - 网络选拔赛 A】【构造】Vertex Cover

48 篇文章 0 订阅
24 篇文章 0 订阅

Vertex Cover

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others)
Total Submission(s): 131    Accepted Submission(s): 48
Special Judge


Problem Description
As we know,  minimumvertexcover  is a classical NP-complete problem. There will not be polynomial time algorithm for it unless  P=NP .

You can see the definition of vertex cover in https://en.wikipedia.org/wiki/Vertex_cover.

Today, little M designs an "approximate" algorithm for vertex cover. It is a greedy algorithm. The main idea of her algorithm is that always choosing the maximum degree vertex into the solution set. The pseudo code of her algorithm is as follows:

We assume that the labels of the vertices are from 1 to n.
for (int i = 1; i <= n; ++i) {
  use[i] = false;
    deg[i] = degree of the vertex i;
}
int ans = 0;
while (true) {
  int mx = -1, u;
    for (int i = 1; i <= n; ++i) {
      if (use[i])
          continue;
        if (deg[i] >= mx) {
          mx = deg[i];
            u = i;
        }
    }
    if (mx <= 0)
      break;
    ++ans;
    use[u] = true;
    for (each vertex v adjacent to u)
      --deg[v];
}
return ans;


As a theory computer scientist, you immediately find that it is a bad algorithm. To show her that this algorithm dose not have a constant approximate factor, you need to construct an instance of vertex cover such that the solution get by this algorithm is much worse than the optimal solution.

Formally, your program need to output a simple undirected graph of at most  500  vertices. Moreover, you need to output a vertex cover solution of your graph. Your program will get Accept if and only if the solution size get by the above algorithm is at least three times as much as yours. 
 

Input
There is no input.
 

Output
First, output two integer  n  and  m  in a line, separated by a space, means the number of the vertices and the number of the edges in your graph.
In the next  m  lines, you should output two integers  u  and  v  for each line, separated by a space, which denotes an edge of your graph. It must be satisfied that  1u,vn  and your graph is a simple undirected graph.
In the next line, output an integer  k(1kn) , means the size of your vertex cover solution.
Then output  k  lines, each line contains an integer  u(1un)  which denotes the label of a vertex in your solution. It must be satisfied that your solution is a vertex cover of your graph.
 

Sample Output
  
  
4 4 1 2 2 3 3 4 4 1 2 1 3
Hint
The sample output is just to exemplify the output format.
 

Source

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 512, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
vector< pair<int, int> >edge;
int ind[N];
vector<int>vt[N];
int check()
{
	bool use[N];
	int deg[N];
	for (int i = 1; i <= 256; ++i)
	{
		use[i] = false;
		deg[i] = ind[i - 1];
	}
	int ans = 0;
	while (true)
	{
		int mx = -1, u;
		for (int i = 1; i <= 256; ++i)
		{
			if (use[i])continue;
			if (deg[i] >= mx)
			{
				mx = deg[i];
				u = i;
			}
		}
		if (mx <= 0)break;
		++ans;
		use[u] = true;
		for (auto v : vt[u])
		{
			--deg[v];
		}
	}
	return ans;
}
void solve()
{
	int bas = 64;
	for (int rgt_num = 32; rgt_num >= 1; rgt_num /= 2)
	{
		int lft_num = rgt_num / 2;
		if (lft_num == 0)lft_num = 1;
		for (int x = 0; x < 64; ++x)
		{
			int y = x / 2;
			int d = 32 / lft_num;
			for (int tim = 1; tim <= lft_num; ++tim)
			{
				edge.push_back({ x, bas + y });
				++ind[x];
				++ind[bas + y];
				vt[x + 1].push_back(bas + y + 1);
				vt[bas + y + 1].push_back(x + 1);
				y += d;
				y %= 32;
			}
		}
		bas += 32;
	}
	int n = 64 * 4; int m = edge.size();
	printf("%d %d\n", n, m);
	for (auto it : edge)
	{
		printf("%d %d\n", it.first + 1, it.second + 1);
	}
	printf("%d\n", 64);
	for (int i = 0; i < 64; ++i)
	{
		printf("%d\n", i + 1);
	}
}
int main()
{
	solve();
	return 0;
}
/*
【题意】
http://acm.hdu.edu.cn/showproblem.php?pid=6150
"最小点覆盖集"是个NP完全问题
有一个近似算法是说————
每次选取度数最大的点(如果有多个这样的点,则选择最后一个)
让你构造一个图,使得其近似算法求出来点数是你给定的覆盖点数的至少3倍。

【分析】
即,我们要构造一种覆盖方案,使得我们选取的点数尽可能少,其算法选取的点数尽可能多。

这里比较容易想到二分图。
然后二分图的最小答案肯定只要是min(左边点数,右边点数)

我们不妨使得左边的点数比较少,右边的点数比较多。
在这种情况下,我们的选择方案就可以是左边的所有点。
而我们希望其贪心策略选择的尽量是右边的点。

==========================================================================
我的构造方案——见代码
左边64个点,右边6组,每组32个点,每个点的边数依次为{32, 16, 8, 4, 2, 1}
==========================================================================
ICPC Camp解法
左边n个点(编号较小),
对于每个i∈[1, n],右边新建n / i 个点,每个点选择左边i个点连一条边(总边数为n^2),使得每个i最多只使得左边每个点的度数+1
这样左边每个点的度数都是<=n的,而右边点每个点的度数会分别是{1 } {2 } {3 } {4 } ... {n }
这样每次会选右边的点去除,去除之后左边的度数依旧<=右边的度数

于是贪心做法会选择右边,大小为nlogn的点集,
而实际只需要选择左边,大小为n的点集即可。

【时间复杂度&&优化】
O(n ^ 2)

*/


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值