我是傻B我是傻B我是傻B!!
真是太差了居然看题解看了半个小时也没看懂!!真差!!
贪心。
Description
Farmer John决定为他的所有奶牛都配备手机,以此鼓励她们互相交流。不过,为此FJ必须在奶牛们居住的N(1 <= N <= 10,000)块草地中选一些建上无线电通讯塔,来保证任意两块草地间都存在手机信号。所有的N块草地按1..N 顺次编号。 所有草地中只有N-1对是相邻的,不过对任意两块草地A和B(1 <= A <= N; 1 <= B <= N; A != B),都可以找到一个以A开头以B结尾的草地序列,并且序列中相邻的编号所代表的草地相邻。无线电通讯塔只能建在草地上,一座塔的服务范围为它所在的那块草地,以及与那块草地相邻的所有草地。 请你帮FJ计算一下,为了建立能覆盖到所有草地的通信系统,他最少要建多少座无线电通讯塔。
Input
* 第1行: 1个整数,N
* 第2..N行: 每行为2个用空格隔开的整数A、B,为两块相邻草地的编号
Output
* 第1行: 输出1个整数,即FJ最少建立无线电通讯塔的数目
Sample Input
5
1 3
5 2
4 3
3 5
输入说明:
Farmer John的农场中有5块草地:草地1和草地3相邻,草地5和草地2、草地
4和草地3,草地3和草地5也是如此。更形象一些,草地间的位置关系大体如下:
(或是其他类似的形状)
4 2
| |
1--3--5
Sample Output
2
输出说明:
FJ可以选择在草地2和草地3,或是草地3和草地5上建通讯塔。
人话题意:选取最少的点覆盖整个树。一个点覆盖的范围是以该点为中心的菊花。(自己及其相邻的点)。
贪心依据:叶子结点不用去选,因为选他的父亲反正也是能覆盖他,显然选父亲更优。
当我们选了一个点之后,我们就可以认为他的儿子都被删掉了。因为是递归求解,不会存在儿子的子树中还有没覆盖的。
然后就可以视为出现新的叶子结点了。继续求解。。。。
具体来说把对于一个节点u,如果是叶子结点(不一定是原图里的,是在删完点后的),根据贪心依据,我们去选他的父亲。把所有儿子是否被选的bool变量或起来。如果结果为1表示有儿子被选,那么u跟着也就被覆盖了不能被视为叶子。否则还要检查一下自己是否在遍历儿子的时候因为儿子是叶子被选中。还要检查父亲是否因为兄弟是叶子被选中,如果父亲被选那么u还是被覆盖了的。如果三个条件都符合即说明u是叶子。
代码贴黄学长的叭~
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<cmath> #define inf 0x7fffffff #define ll long long using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,cnt,ans; int head[10005]; bool mark[10005]; struct data{int to,next;}e[20005]; inline void insert(int u,int v) { e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt; } void getans(int x,int fa) { bool flag=0; for(int i=head[x];i;i=e[i].next) { if(e[i].to==fa)continue; getans(e[i].to,x); if(mark[e[i].to])flag=1; } if(!flag&&!mark[x]&&!mark[fa]){ans++;mark[fa]=1;} } int main() { n=read(); for(int i=1;i<n;i++) { int u=read(),v=read(); insert(u,v); insert(v,u); } getans(1,0); printf("%d",ans); return 0; }
OTZ。。话说还有树dp我太弱不会就没写啊啊。。。