Hdu1011:星舰部队(java实现)

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1011
题目名称:星舰部队
问题描述:
作为星河战队的领导者,你被派去摧毁这些虫子的基地。
基地为一个个房间连成的树形结构,每个房间都被一些虫子占据,里面也对应一定的大脑在房间里。
你必须在每个房间留下一些士兵来对抗里面的所有虫子。一个星舰士兵可以对抗20个虫子。
由于你没有足够的士兵,你只能清理一些房间,让神经气体完成其余的工作(无法获得大脑)。
计算最大所有可获得大脑的总和。
输入项:
输入包含多个测试用例。
从第一行开始,n m分别表示房间个数和士兵数。
接下来n行中每行为a b分别表示房间内的虫子数和大脑数
接下来的n-1行中每行为x y分别为表示房间连接情况,房间为树形连接,且无法退回
然后接着是下一个测试用例,直到-1 -1表示结束
输出项:
每一个测试用例可以捕获的大脑总数
解题技巧:
背包算法(参考ACM课本98页0-1背包),士兵是动态变多的,问题是从最后一个往上考虑的
测试用例:
5 10
50 10
40 10
40 20
65 30
70 30
1 2
2 4
1 3
2 5
1 1
20 7
-1 -1
输出结果:
50
7

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Hdu1011 {
    //每一次任务的前提所给信息
    static ArrayList<Integer> roomsList[];//这是一个List的数组 每一个数组中存储
    static int n, m;//n表示房间个数,m表示士兵个数
    static int bugs_brains[][];//房间的虫子数和大脑的数量

    static int dp[][];//dp[i][j]表示第i个洞消耗j个士兵的获得值
    static boolean vis[];//标记本节点是否被遍历过

    public static void main(String[] args) {
        List<Hdu1011DataStructure> hdu1011DataStructureList = read();//读取输入的内容
        for (Hdu1011DataStructure hdu1011DataStructure : hdu1011DataStructureList) {
            System.out.println(count(hdu1011DataStructure));//对每次任务计算并输出最终结果
        }
    }

    //单个准备工作
    static int count(Hdu1011DataStructure hdu1011DataStructure) {
        m = hdu1011DataStructure.getM();
        if (m == 0) {//表示一开始就没有士兵
            return 0;
        }
        n = hdu1011DataStructure.getN();
        vis = new boolean[n + 1];//默认初始值为false
        dp = new int[n + 1][m + 1];//初始值都为0
        roomsList = hdu1011DataStructure.getRooms();
        bugs_brains = hdu1011DataStructure.getBugs_brains();
        //单个准备工作完毕
        dfs_dp(1);//从1开始
        return dp[1][m];
    }

    static void dfs_dp(int a) {//a表示节点编号
        vis[a] = true;//标记本节点已经遍历了
        int temp = (bugs_brains[a][0] + 19) / 20;//本节点需要的士兵
        for (int i = temp; i <= m; i++)//在dp的第a行temp之后的内容都存放可以获得的大脑数量
            dp[a][i] = bugs_brains[a][1];//dp表示第a个洞穴,消耗i个士兵获得的大脑,投入再多的士兵也只能获得这些大脑
        for (int i = 0; i < roomsList[a].size(); i++) {//找到本节点所能到的节点
            int to = roomsList[a].get(i);
            if (vis[to] == true) continue;//如果已经弄完了,就不用弄了
            dfs_dp(to);//处理下一个节点,到最后一次,dp中temp之后都存放了能获得的大脑数
            for (int j = m; j >= temp; j--) {//j表示从temp到m所在的列数,重新修改a节点消耗temp个士兵所获得的大脑数,加上了子节点
                for (int k = 1; k <= j - temp; k++)//
                    dp[a][j] = Math.max(dp[a][j], dp[a][j - k] + dp[to][k]);//da[a][j-k]从第1列到temp列,表示还没有被修改
            }
        }
    }


    static List<Hdu1011DataStructure> read() {
        Scanner scanner = new Scanner(System.in);
        String nm[] = scanner.nextLine().split(" ");

        List<Hdu1011DataStructure> hdu1011DataStructureList = new ArrayList<>();
        while (!nm[0].equals("-1")) {
            int n = Integer.parseInt(nm[0]);
            Hdu1011DataStructure h1011DataStructure = new Hdu1011DataStructure();
            h1011DataStructure.setN(n);
            h1011DataStructure.setM(Integer.parseInt(nm[1]));
            //存放虫子数量和大脑数量n行
            int bugs_brains[][] = new int[n + 1][2];
            for (int i = 1; i < n + 1; ++i) {
                String bug_brain[] = scanner.nextLine().split(" ");
                bugs_brains[i][0] = Integer.parseInt(bug_brain[0]);
                bugs_brains[i][1] = Integer.parseInt(bug_brain[1]);
            }
            h1011DataStructure.setBugs_brains(bugs_brains);//得到本次的大脑和虫子
            //存放房间的情况n-1行
            roomsList = new ArrayList[n + 1];//计数从1开始
            for (int i = 0; i < roomsList.length; i++) {//初始化
                roomsList[i] = new ArrayList<Integer>();
            }
            for (int i = 0; i < n - 1; i++) {
                String room[] = scanner.nextLine().split(" ");
                int a = Integer.parseInt(room[0]);
                int b = Integer.parseInt(room[1]);
                roomsList[a].add(b);
                roomsList[b].add(a);
            }
            h1011DataStructure.setRooms(roomsList);//得到本次的房间关系

            hdu1011DataStructureList.add(h1011DataStructure);
            nm = scanner.nextLine().split(" ");
        }
        return hdu1011DataStructureList;
    }
}

对应数据结构(Java对象):

import java.util.ArrayList;
import java.util.Arrays;

public class Hdu1011DataStructure {
    private int n, m;//n表示房间个数,m表示士兵数量
    private int bugs_brains[][];//i 0表示虫子数,i 1表示大脑数量
    private ArrayList<Integer> rooms[];//数组i=1中的列表中的内容为1所能到的节点

    @Override
    public String toString() {
        return "Hdu1011DataStructure{" +
                "n=" + n +
                ", m=" + m +
                ", bugs_brains=" + Arrays.toString(bugs_brains) +
                ", rooms=" + rooms +
                '}';
    }

    public ArrayList<Integer>[] getRooms() {
        return rooms;
    }

    public void setRooms(ArrayList<Integer>[] rooms) {
        this.rooms = rooms;
    }

    public int getN() {
        return n;
    }

    public void setN(int n) {
        this.n = n;
    }

    public int getM() {
        return m;
    }

    public void setM(int m) {
        this.m = m;
    }

    public int[][] getBugs_brains() {
        return bugs_brains;
    }

    public void setBugs_brains(int[][] bugs_brains) {
        this.bugs_brains = bugs_brains;
    }
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值