Strategic Game(树形DP)

原题地址
Problem Description
Bob enjoys playing computer games, especially strategic games, but sometimes he cannot find the solution fast enough and then he is very sad. Now he has the following problem. He must defend a medieval city, the roads of which form a tree. He has to put the minimum number of soldiers on the nodes so that they can observe all the edges. Can you help him?

Your program should find the minimum number of soldiers that Bob has to put for a given tree.

The input file contains several data sets in text format. Each data set represents a tree with the following description:

the number of nodes
the description of each node in the following format
node_identifier:(number_of_roads) node_identifier1 node_identifier2 … node_identifier
or
node_identifier:(0)

The node identifiers are integer numbers between 0 and n-1, for n nodes (0 < n <= 1500). Every edge appears only once in the input data.

For example for the tree:

在这里插入图片描述

the solution is one soldier ( at the node 1).

The output should be printed on the standard output. For each given input data set, print one integer number in a single line that gives the result (the minimum number of soldiers). An example is given in the following table:

Sample Input

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)

Sample Output

1
2
题目的意思是:在一颗树的节点上驻守士兵,每个士兵能看守所有的邻接边。问:要看守这棵树的所有的边,至少要多少个士兵。
简单说一下贪心策略:

  • dp[u][0]表示如果u节点不驻守士兵,以u为根节点的子树至少需要驻守多少士兵
  • dp[u][1]表示如果u节点驻守士兵,以u为根节点的子树至少需要驻守多少士兵
    一般地 d p [ u ] [ 0 ] = Σ ( d p [ v ] [ 1 ] ) dp[u][0]=\Sigma(dp[v][1])
    d p [ u ] [ 1 ] = 1 + Σ ( m i n ( d p [ v ] [ 0 ] , d p [ v ] [ 1 ] ) ) dp[u][1]=1+\Sigma(min(dp[v][0],dp[v][1]))
  • 第一个式子表示如果根节点不驻兵,那么子树的根结点必须驻兵。
  • 第二个式子表示如果根节点驻兵,那么子树的根节点可以驻兵,也可以不驻兵,此外还要加上根节点驻守的一个士兵。
    原题的输入是按照层次遍历的方式输入的,而且后面紧接着输入孩子节点。所以用邻接表是比较方便的,且BFS的时候也不用作标记。代码已经十分简洁了,仅供参考。
    因为树是二分图,所以也可以用匈牙利算法求最大点覆盖,有兴趣的可以自己尝试一下。
#include<cstdio>
#include<cstring>
#include <vector>
#include<algorithm>
using namespace std;
int n,dp[1500][2];
vector<int> vec[1500];
void DFS(int subRoot)
{
    dp[subRoot][1]=1,dp[subRoot][0]=0;
    for(int i=0;i<vec[subRoot].size();i++)
    {
        int cur=vec[subRoot][i];
        DFS(cur);
        dp[subRoot][0]+=dp[cur][1];
        dp[subRoot][1]+=min(dp[cur][0],dp[cur][1]);
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        int root,father,num,child;
        memset(dp,0,sizeof(dp));
        for(int i=0;i<n;i++)
        {
            scanf("%d:(%d)",&father,&num);
            if(i==0) root=father;
            for(int j=0;j<num;j++)
            {
                scanf("%d",&child);
                vec[father].push_back(child);
            }
        }
        DFS(root);
        printf("%d\n",min(dp[root][0],dp[root][1]));
        for(int i=0;i<n;i++) vec[i].clear();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40634175/article/details/88584474
今日推荐