UVA - 10859 —— Placing Lampposts
题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34290
这道题是一道在树上面搜索的好题,要注意以下几点:
1. 如何将该问题转化为最小化问题?而且这个最小化问题有两个最小化目标,首要的是“点数”,其次是“仅被一盏灯照亮的边数”
2. 无根树转有根数来搜索,而且注意整幅图是无向五环图,即“森林”,搜索要考虑到所有森林中的树
3. 每个节点的决策其实就是决定是否要在该节点上放置灯笼,“放” 与 “不放” 会引发不同的搜索方式,每一种决策的代价加上该节点下的所有字子树的带来的代价之和就是整体的代价,我们要找到是放的整体代价小,还是不放的小。
4. 因为都是树的搜索,所以肯定不会搜索到重复的状态,否则就有回路存在了,不满足树的定义。
#include <cstdio> #include <iostream> #include <cstring> #include <vector> using namespace std; const int M = 1005; const int MAXN = (int) 1e9; vector<int> E[M]; bool vis[M]; int dfs(int u, int fa, bool ok) { vis[u] = 1; int ret1 = 0, ret2 = MAXN, cur; // 1 ret1 = M; if(fa != -1 && !ok) ret1++; for(int i=0; i<E[u].size(); i++) { int v = E[u][i]; if(v==fa) continue; ret1 += dfs(v, u, 1); } // 0 if(fa == -1 || ok) { ret2 = 0; if(ok) ret2++; for(int i=0; i<E[u].size(); i++) { int v = E[u][i]; if(v==fa) continue; ret2 += dfs(v, u, 0); } } return min(ret1, ret2); } int main () { int T, n, m; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &m); int a, b; for(int i=0; i<m; i++) { scanf("%d%d", &a, &b); E[a].push_back(b); E[b].push_back(a); } int ans = 0; for(int i=0; i<n; i++) { if(!vis[i]) { ans += dfs(i, -1, 0); } } a = ans / M, b = ans % M; printf("%d %d %d\n", a, m-b, b); memset(vis, 0, sizeof(vis)); memset(E, 0, sizeof(E)); } return 0; }