这道题贪心DP都可以做,但是贪心的正确性容易证明,因为子树合并一定不会劣与合并,那么我就贪心了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
const int INF=0x3f3f3f3f;
const int maxn = 10005;
struct Edge
{
int to,next;
}edge[maxn<<1];
int head[maxn];
int maxedge;
inline void addedge(int u,int v)
{
edge[++maxedge] = (Edge) { v,head[u] };
head[u] = maxedge;
edge[++maxedge] = (Edge) { u,head[v] };
head[v] = maxedge;
}
int n;
inline void init()
{
scanf("%d",&n);
memset(head,-1,sizeof(head));
maxedge=-1;
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
}
}
int f[maxn];
bool flag[maxn];
void dfs(int u,int father)
{
int cnt=0;
f[u]=1;
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v==father) continue;
dfs(v,u);
f[u]+=f[v];
if(!flag[v]) cnt++;
}
if(cnt>=2) f[u]-=2,flag[u]=true;
else if(cnt==1) f[u]-=1;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
#endif
int cas;
scanf("%d",&cas);
while(cas--)
{
init();
memset(flag,0,sizeof(flag));
dfs((n+1)>>1,-1);
printf("%d\n",f[(n+1)>>1]);
}
return 0;
}

该博客介绍了如何使用贪心策略解决bzoj 1907题目,强调贪心算法的正确性在于子树合并总是优于不合并,从而提供了一个简洁的解决方案。

805

被折叠的 条评论
为什么被折叠?



