1054 Strategic Game 树形DP

 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

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

 
#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;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值