1054 Strategic Game 树形DP

来源:互联网 发布:贪吃蛇c编程 编辑:程序博客网 时间:2024/05/16 10:03

 Strategic Game

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 2296    Accepted Submission(s): 919


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:

hdu <wbr>1054 <wbr>Strategic <wbr>Game

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

40:(1) 11:(2) 2 32:(0)3:(0)53:(3) 1 4 21:(1) 02:(0)0:(0)4:(0)

Sample Output

12

 
#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;int dp[1505][2];int vis[1505],head[1505];int len,root;//全局变量struct node{    int now,next;}tree[3005];//由于是双向创建的,因此大小需要为需求的2倍//即(x,y)一个边两个数void add(int x,int y){//创建树,将结点加入到树中        tree[len].now=y;    tree[len].next=head[x];    head[x]=len++;        tree[len].now=x;    tree[len].next=head[y];    head[y]=len++;        //这是将边(x,y)加入到树中,然后利用head来记录下下一个的位置    }void dfs(int root){        int i,k;    vis[root]=1;    dp[root][1]=1; //表示这个节点选了    dp[root][0]=0; //表示这个节点没选        for(i=head[root];i!=-1;i=tree[i].next){                k=tree[i].now;        if(!vis[k]){            dfs(k);//深度优先搜索,一直遍历到没有子节点的节点,不断的用k去指向下一个,            //然后利用动态规划去保存            dp[root][0]+=dp[k][1];//如果这个点不选,则其保存相当于子结点中选了的那个(因为不选的话子结点会空出来)            dp[root][1]+=min(dp[k][1],dp[k][0]);//如果这个点选,则要在在子节点找最小的            //如果选了这个点,则其子结点可选可不选,则在其中找个小的,保存起来            //注意一开始定义已经dp[root][1]=1,因此不需要再加1了,已经默认加1            //注意是递归,root会变的。        }    }}int main(){        freopen("/Users/qigelaodadehongxiaodi/Desktop/data1.txt", "r", stdin);    //这个不理,是用来方便输入输出的东西,利用文本输入流来读取数据    //提交代码的时候记得注销这条语句            int t,x,y,n,j;                    while(~scanf("%d",&t)){        len=0;        root=-1;        memset(dp,0,sizeof(dp));        memset(vis,0,sizeof(vis));        memset(head,-1,sizeof(head));        for(j=1;j<=t;j++){            scanf("%d:(%d)",&x,&n);            if(root==-1)                root=x;            for(int i=0;i<n;i++){                scanf("%d",&y);                add(x,y);//这是x、y的边,加入到树中            }        }                dfs(root);//深度优先搜索        printf("%d\n",min(dp[root][0],dp[root][1]));            }        return 0;}



0 0