#第一周1005结题报告#

来源:互联网 发布:广告单页设计软件 编辑:程序博客网 时间:2024/05/23 01:12

第一周1005结题报告

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
题目意思是以最少的士兵覆盖图中所有道路,刚开始想到用贪心算法,搞了一个n*n的数组,循环处理节点信息,超时,优化了一下贪心算法,复杂度到O(n*n)依然超时,疯了,拿原题百度了一下,树形DP,然而我以前并不知道这是什么,后来仔细研究了一下dp与树形dp,写了,一直wa,检查了两天,一直改,后来上厕所的时候忽然想起来状态转移方程写错了。
每个点要么有士兵,要么没士兵,两种状态,用dp【n】【1】和dp【n】【0】分别表示n点有士兵和n点没士兵的最优解,即最少士兵的个数,包括他本身,因此开始时初始化dp【n】【1】为1,若此点有士兵,则

dp[node][1] +=Math.min(dp[i][0],dp[i][1]);表示儿子节可以有,可以没有,取其最优

若此点没有士兵,子节点必须有

dp[node][0] +=dp[i][1];

然后用递归求出每个点的两种状态,最后取根节点的最优即为结果。
java代码如下:

package 第一周;import java.util.Scanner;public class Main1005_2 {    public static int[] father;//父节点    public static int[] visit;//访问标记    public static int[][] dp;//存储状态    public static int child[];//子节点最终没用    public static void treeDp(int node) {         visit[node]  = 1;//      if(child[node]==0){//          dp[node][0]= 0;//          dp[node][1] = 1;//          //      }//      if(child[node]==1){//          dp[node][0]=1;//          dp[node][1]=1;//          //      }        for(int i=0;i<visit.length;i++){//递归dp算法            if(visit[i]!=1&&father[i]==node){                treeDp(i);                dp[node][1] +=Math.min(dp[i][0],dp[i][1]);                dp[node][0] +=dp[i][1];            }        }    }    public static void main(String args[]) {        Scanner sc = new Scanner(System.in);        while (sc.hasNext()) {            int n = Integer.parseInt(sc.nextLine());            dp = new int[n][2];// dp[n][1]表示n点选择时的动态规划最优情况            // dp[n][0]表示n点不选时动态规划最优情况            father = new int[n];            visit = new int[n];            child = new int[n];            int root = 0;            for(int x =0;x<n;x++){                father[x] = -1;            }            for (int i = 0; i < n; i++) {                dp[i][1] = 1;                String s1 = sc.nextLine();                String s11[] = s1.split("\\:|\\)|\\(|\\s+");//拆分输入的字符串,总是出现没有自己想要的拆分结果,正则表达式搞清楚                for (int j = 0; j < Integer.parseInt(s11[2]); j++) {//初始化父节点                    father[Integer.parseInt(s11[j + 4])] = Integer                            .parseInt(s11[0]);                }                child[Integer.parseInt(s11[0])] = Integer.parseInt(s11[2]);            }            while(father[root]>-1){//找到根节点                root = father[root];            }            treeDp(root);            System.out.println(Math.min(dp[root][0],dp[root][1]));        }    }}
0 0
原创粉丝点击