标签:namespace 思路 std cto for 代码 输入 print set
题意:
给出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 }
标签:namespace 思路 std cto for 代码 输入 print set
原文地址:https://www.cnblogs.com/kickit/p/8997016.html