您的位置:首页 > 其它

[BZOJ1907]树的路径覆盖(贪心)

2017-09-24 21:06 274 查看

题目:

我是超链接

题解:

看上去像网络瘤题?嗯很明显想多了,这可是一棵树啊

然后陷入一脸不可做的状态。。

翻翻翻…..

以某一个点为根的子树,这个点只有两种状态:拐弯(两条简单路径在一个点交汇成一条,折折折)和直上(一条路走到黑)

我们优先满足拐弯的情况,贪心!贪心策略是:只要当前点能成为拐点,就让它成为拐点。也就是说,贪心地将它能连的儿子连起来。因为一个拐点可以使减少2个点,而拉上ta只能减少一个点,所以这个贪心的策略是正确的。

我们对于每个点维护是否已经拐过弯了(因为只有没拐过弯的节点才能继续走到顶)

size[i]表示以i为根节点的子树的最小路径覆盖



貌似还有一种树形dp的方法?

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#define N 10005
using namespace std;
int tot,nxt[N*2],point
,v[N*2],size
;bool vis
;
void cl(){tot=0; memset(point,0,sizeof(point));memset(size,0,sizeof(size));memset(vis,0,sizeof(vis));}
void addline(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void dfs(int x,int fa)
{
int cnt=0;
size[x]=1;
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa)
{
dfs(v[i],x);
size[x]+=size[v[i]];
if (!vis[v[i]]) cnt++;
}
if (cnt>=2) size[x]-=2,vis[x]=true;//可以被当做一个拐点,折起来节点数-2
else if (cnt==1) size[x]--;//只能和这个点一起走到顶
}
int main()
{
int T,i,n;
scanf("%d",&T);
while (T--)
{
cl
4000
();
scanf("%d",&n);
for (i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
addline(x,y);
}
dfs(1,0);
printf("%d\n",size[1]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: