树形DP
【例题1】MZOJ1063 士兵守卫
http://61.139.95.227:82/problem.php?id=1063
题目描述
Bob特别喜欢战略游戏,但有时他不能尽快找到最优解,所以他就很伤心。现在他又有一个问题,他必须保卫一个中世纪的城市,这个城市的道路形成了一棵树。他需要在树的节点上放最少的士兵来观察所有的边。你能帮助他么?
例如下图就只需要一个士兵放在1号节点。
输入
输入文件中有多组数据,每组数据的第一行N表示点的个数。接下来N行每行格式如下
x:(k) a1 a2 … ak(x为点的编号,k为与其相连的子节点个数,a1, a2, …, ak分别为子节点的编号)
输出
对于每组数据输出一行一个数,即最少士兵数。
样例输入
4
0:(1) 1
1:(2) 2 3
2:(0)
3:(0)
5
3:(3) 1 4 2
1:(1) 0
2:(0)
0:(0)
4:(0)
样例输出
1
2
提示
0 < N<= 1500, 0
0 <= x < N
【代码】
#include <bits/stdc++.h>
using namespace std;
const int MAXN=15000+5;
int n,f[MAXN][5];
int size=0;
int head[MAXN];
struct node
{
int u;
int v;
int next;
}edge[MAXN<<1];
void add(int u,int v)
{
edge[size].u=u;
edge[size].v=v;
edge[size].next=head[u];
head[u]=size++;
}
inline int read()
{
int X=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9')
{
X=(X<<1)+(X<<3)+ch-'0';
ch=getchar();
}
return X;
}
void dp(int u,int fa)
{
f[u][0]=0; f[u][1]=1;
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].v;
if(v==fa) continue;
dp(v,u);
f[u][0]+=f[v][1];
f[u][1]+=min(f[v][0],f[v][1]);
}
}
int main()
{
freopen("input.txt","r",stdin);
while(scanf("%d",&n)!=EOF)
{
memset(head,-1,sizeof(head));
int u,v,t;
for(int i=1;i<=n;i++)
{
scanf("%d:(%d)",&u,&t);
for(int i=1;i<=t;i++)
{
scanf("%d",&v);
add(u,v);
add(v,u);
}
}
dp(0,-1);
printf("%d\n",min(f[0][0],f[0][1]));
}
return 0;
}
【例题2】 MZOJ1264 longest
http://61.139.95.227:82/problem.php?id=1264
题目描述
乌托邦有n个城市,某些城市之间有公路连接。任意两个城市都可以通过公路直接或者间接到达,并且任意两个城市之间有且仅有一条路径(What does this imply? A tree!)。
每条公路都有自己的长度,这些长度都是已经测量好的。
小修想从一个城市出发开车到另一个城市,并且她希望经过的公路总长度最长。请问她应该选择哪两个城市?这个最长的长度是多少?
输入
第一行n(n<=1000)。
以下n-1行每行三个整数a, b, c。表示城市a和城市b之间有公路直接连接,并且公路的长度是c(c<=10000)。
输出
仅一个数,即最长长度。
样例输入
5
1 2 2
2 3 1
2 4 3
1 5 4
样例输出
9
说明
从城市4到城市5,经过的路径是4-2-1-5,总长度是9。
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1005;
int n,ans=0,f[MAXN][5];
int size=0;
int head[MAXN];
struct node
{
int u;
int v;
int w;
int next;
}edge[MAXN<<1];
void add(int u,int v,int w)
{
edge[size].u=u;
edge[size].v=v;
edge[size].w=w;
edge[size].next=head[u];
head[u]=size++;
}
inline int read()
{
int X=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9')
{
X=(X<<1)+(X<<3)+ch-'0';
ch=getchar();
}
return X;
}
inline int write(int X)
{
if(X<0) {putchar('-'); X=~(X-1);}
int s[20],top=0;
while(X) {s[++top]=X%10; X/=10;}
if(!top) s[++top]=0;
while(top) putchar(s[top--]+'0');
}
void readdata()
{
memset(head,-1,sizeof(head));
n=read();
for(int i=1;i<n;i++)
{
int u=read(),v=read(),w=read();
add(u,v,w);
add(v,u,w);
}
}
void dp(int u,int fa)
{
f[u][0]=0; f[u][1]=0;
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].v,w=edge[i].w;
if(v==fa) continue;
dp(v,u);
int dis=f[v][0]+w;
if(dis>f[u][0])
{
f[u][1]=f[u][0];
f[u][0]=dis;
}
else if(dis>f[u][1])
{
f[u][1]=dis;
}
ans=max(ans,f[u][1]+f[u][0]);
}
}
void work()
{
dp(1,0);
write(ans);
}
void init()
{
freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
}
int main()
{
init();
readdata();
work();
return 0;
}