scu 4439 Vertex Cover

题意:

给出n个点,m条边,将若干个点染色,使得每个边至少有一点染色,问至少染多少个点。

思路:

如果是二分图,那就是最小点覆盖,但是这是一般图。

一般图的最小覆盖是npc问题,但是这题有一个条件比较特殊,就是输入的每条边都保证了至少有一个点小于等于30,所以至多覆盖30个点就可以了。

那么就可以用搜索解决,对于一个点,要么覆盖,要么不覆盖。

如果这个点被覆盖了,就直接往下搜;

如果没有被覆盖,那么就要么覆盖这个点,直接往下搜;要么不覆盖这个点,但把这个点相邻的点全部覆盖,再往下搜。

得剪枝,可行性剪枝和最优性剪枝。

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include <vector>
 5 using namespace std;
 6 const int N = 505;
 7 int vis[N];
 8 vector<int> g[N];
 9 int tot;
10 int ans;
11 void dfs(int cu,int sum)
12 {
13     if (sum > ans) return;
14     if (cu > tot)
15     {
16         ans = sum;
17         return;
18     }
19     if (vis[cu]) dfs(cu+1,sum);
20     else
21     {
22         vis[cu]++;
23         dfs(cu+1,sum+1);
24         vis[cu]--;
25         for (auto x : g[cu])
26         {
27             if (!vis[x]) sum++;
28             vis[x]++;
29         }
30         dfs(cu+1,sum);
31         for (auto x : g[cu])
32         {
33             vis[x]--;
34             if (!vis[x]) sum--;
35         }
36     }
37 }
38 int main()
39 {
40     int n,m;
41     while (scanf("%d%d",&n,&m) != EOF)
42     {
43         tot = 0;
44         ans = 10000;
45         memset(vis,0,sizeof(vis));
46         for (int i = 1;i <= n;i++) g[i].clear();
47         for (int i = 0;i < m;i++)
48         {
49             int x,y;
50             scanf("%d%d",&x,&y);
51             g[x].push_back(y);
52             g[y].push_back(x);
53         }
54         tot = min(30,n);
55         ans = tot;
56         dfs(1,0);
57         printf("%d\n",ans);
58     }
59     return 0;
60 }

 

posted @ 2018-05-06 02:05  qrfkickit  阅读(195)  评论(0编辑  收藏  举报