题目链接:http://acm.pku.edu.cn/JudgeOnline/problem?id=3659
这题不算难题了,基本算是中等题
题目大意是给出一颗树,在一些点建一个信号塔,信号塔覆盖范围是其所在点和邻近点,问最少几个信号塔可以覆盖全区域
思路是树状DP(后序遍历),有三个状态,分别记录父节点建塔,本节点建塔和子节点建塔的最少建塔数量
需要注意的就是子节点建塔的判断,子节点建塔只要一个以上的子节点建塔即可
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
struct node
{
vector<int> linkto;
int build[3];//0 为自己建塔, 1 为父节点建塔, 2为子节点建塔
};
node pasture[10005];
int calcPos(int pos, int f);
int main()
{
int i, j, n, a, b, res;
scanf("%d", &n);
for(i = 0; i < n - 1; i ++)
{
scanf("%d %d", &a, &b);
pasture[a - 1].linkto.push_back(b - 1);
pasture[b - 1].linkto.push_back(a - 1);
}
calcPos(0, 0);
res = min(pasture[0].build[0], pasture[0].build[2]);
printf("%d\n", res);
return 0;
}
int calcPos(int pos, int f)
{
int i, tmp;
bool flag = false;
pasture[pos].build[0] = 1;
pasture[pos].build[1] = 0;
pasture[pos].build[2] = 0;
for(i = 0; i < pasture[pos].linkto.size(); i ++)
{
if(pasture[pos].linkto[i] != f)
{
calcPos(pasture[pos].linkto[i], pos);
pasture[pos].build[0] += min(min(pasture[ pasture[pos].linkto[i] ].build[0], pasture[ pasture[pos].linkto[i] ].build[1])
, pasture[ pasture[pos].linkto[i] ].build[2]);
pasture[pos].build[1] += min(pasture[ pasture[pos].linkto[i] ].build[0], pasture[ pasture[pos].linkto[i] ].build[2]);
pasture[pos].build[2] += min(pasture[ pasture[pos].linkto[i] ].build[0], pasture[ pasture[pos].linkto[i] ].build[2]);
flag = flag || (pasture[ pasture[pos].linkto[i] ].build[0] <= pasture[ pasture[pos].linkto[i] ].build[2]);
}
}
if(pasture[pos].build[2] == 0)
{
pasture[pos].build[2] = 100000;
return 0;
}
if(flag == false)
{
tmp = 100000;
for(i = 0; i < pasture[pos].linkto.size(); i ++)
{
if(pasture[pos].linkto[i] != f
&& pasture[pasture[pos].linkto[i]].build[0] - pasture[pasture[pos].linkto[i]].build[2] < tmp)
tmp = pasture[pasture[pos].linkto[i]].build[0] - pasture[pasture[pos].linkto[i]].build[2];
}
pasture[pos].build[2] += tmp;
}
return 0;
}