赞
踩
WOJ#2532 战略游戏
洛谷P2016 战略游戏
这道题主要是看边的情况。
Bob喜欢玩电脑游戏,特别是战略游戏。但是他经常无法找到快速玩过游戏的办法。现在他有个问题。
他要建立一个古城堡,城堡中的路形成一棵树。他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能瞭望到所有的路。
注意:某个士兵在一个结点上时,与该结点相连的所有边将都可以被瞭望到。
请你编一个程序,给定一棵树,帮Bob计算出他需要放置最少的士兵数。
第一行 N,表示树中结点的数目。
第二行至第N+1行,每行描述每个结点信息,依次为:该结点标号i,k(后面有k条边与结点I相连)。
接下来k个数,分别是每条边的另一个结点标号r1,r2,…,rk。
对于一个n(0<n<=1500)个结点的树,结点标号在0到n-1之间,在输入数据中每条边只出现一次。
输出文件仅包含一个数,为所求的最少的士兵数目。
在一棵树上取若干个点,使得所有边都被连结。求点的个数的最小值。
对于这类最值问题,应当用动态规划求解。
设
s
s
s是树的根,则设
f
[
s
]
f[s]
f[s]表示求以
s
s
s为根的子树上需要安放的最少士兵数量。我们希望用
s
s
s的儿子的对应信息来推出
f
[
s
]
f[s]
f[s]:
s
s
s有放和不放两种可能。当
s
s
s节点放时,它的子节点放和不放都可以;当
s
s
s节点不放时,它的子节点必须放。所以需要加维来表示树的根结点是否选取,才能从子树推算出父亲的最大值。
设 f [ i , 1 ] f[i,1] f[i,1]表示 i i i点放士兵时,以 i i i为根的子树需要的最少士兵数目; f [ i , 0 ] f[i,0] f[i,0]表示 i i i点不放士兵时,以 i i i为根的子树需要的最少士兵数目。
初始条件:
f
[
i
]
[
0
]
=
0
,
f
[
i
,
1
]
=
1
f[i][0]=0,f[i,1]=1
f[i][0]=0,f[i,1]=1;
a
n
s
=
m
i
n
f
[
s
]
[
0
]
,
f
[
s
]
[
1
]
ans=min{f[s][0],f[s][1]}
ans=minf[s][0],f[s][1]。
#include<iostream> #include<cstdio> #include<cctype> using namespace std; const int maxn=1510; int n,s,cnt=2,ans=0; int first[maxn],f[maxn][2]; struct edge {int u,v,w,nxt;}; edge e[maxn<<1]; inline int read() { int x=0;bool f=0;char c=getchar(); while(!isdigit(c)) {f|=c=='-';c=getchar();} while(isdigit(c)) {x=(x<<3)+(x<<1)+(c^48);c=getchar();} return f?-x:x; } inline void add(int u,int v) { e[cnt].u=u;e[cnt].v=v; e[cnt].nxt=first[u];first[u]=cnt++; } inline void dfs(int x,int fa) { f[x][0]=0,f[x][1]=1; for(int i=first[x];i;i=e[i].nxt) { int y=e[i].v; if(y==fa) continue; dfs(y,x); f[x][1]+=min(f[y][0],f[y][1]); f[x][0]+=f[y][1]; } } int main() { n=read(); for(int i=1;i<=n;i++) { int idx=read(),k=read(); for(int j=1;j<=k;j++) { int r=read(); add(idx,r); add(r,idx); } } s=1; dfs(0,-1); ans=min(f[0][0],f[0][1]); cout<<ans; return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。