闯关游戏dfs(优化)

题目:
  闯关游戏,有N关(5<=N<=20),每一关由一些士兵把守,有三种过关方法
  1. 按要求缴纳过路费,通关
  2. 缴纳2倍过路费,当前关卡的士兵可以招募带走
  3. 所带士兵人数超过当前守关人数是可以直接攻打,但需牺牲同样多的士兵
  求通关所需的最少通关费用
附加条件:
  1. 每次招募的士兵最多只能参加3次战斗
  2. 每次战斗牺牲的士兵按照招募的先后次序进行
  3. 每次战斗所有士兵都参加(即对未牺牲的士兵也算一次战斗)

输入:
  1. 第一个数为case数
  2. 每个case中第一个数为关卡数,之后每一个行代表一个关卡
  3. 每个关卡的第一个数为士兵数,第二个数为过关所需费用
输出:
   输出每个case所需的最小过关费用
  #case mincost

代码:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class Breakthrough {

static int[][] barrier;
static int[][] soldier;
static int mincost;
static int n;

public static void main(String[] args) throws FileNotFoundException {
    // TODO Auto-generated method stub
    @SuppressWarnings("resource")
    Scanner sc = new Scanner(System.in);
    sc = new Scanner(new File("files/breakthrough"));
    int T = sc.nextInt();
    for (int t = 0; t < T; t++) {
        n = sc.nextInt();
        barrier = new int[n][2];
        soldier = new int[n][2];
        mincost = 0;
        int tn, tc;
        for (int i = 0; i < n; i++) {
            tn = sc.nextInt();
            tc = sc.nextInt();
            barrier[i] = new int[] { tn, tc };
            mincost += tc;
        }
        dfs(0, 0);
        System.out.println("#" + (t + 1) + " " + mincost);
    }
}

private static void dfs(int step, int cost) {
    // TODO Auto-generated method stub
    if (step == n) {
        if (cost < mincost) {
            mincost = cost;
        }
        return;
    }

    //买关通过
    int tcost = cost + barrier[step][1];
    if (tcost < mincost)
        dfs(step + 1, tcost);

    //买兵通过
    tcost = cost + 2 * barrier[step][1];
    if (tcost < mincost) {
        soldier[step][0] = barrier[step][0];
        soldier[step][1] = 3;
        dfs(step + 1, tcost);
        soldier[step][1] = 0;
    }

    //正面硬刚
    int nos = barrier[step][0];
    int[][] tmps = new int[n][2];
    //判断兵够不够,能不能刚得动
    for (int i = 0; i < n; i++) {
        if (soldier[i][1] > 0) {
            nos -= soldier[i][0];
            if (nos <= 0) {
                //可以刚得动就改变兵力情况,事先备份,以便恢复
                CopyOf(tmps, soldier);
                soldier[i][0] = -nos;
                for (int j = 0; j < n; j++) {
                    if (j < i)
                        soldier[j][0] = 0;
                    soldier[j][1]--;
                }
                dfs(step + 1, cost);
                //恢复
                CopyOf(soldier, tmps);
                break;
            }
        }
    }
}

private static void CopyOf(int[][] a1, int[][] a2) {
    // TODO Auto-generated method stub
    for (int i = 0; i < a2.length; i++) {
        a1[i][0] = a2[i][0];
        a1[i][1] = a2[i][1];
    }
}

}

sample input:
5
7
10 100
70 5
80 15
20 60
50 90
30 80
10 10
9
600 800
300 400
300 400
1000 400
300 600
100 300
600 300
600 500
1000 300
11
1000 10
700 900
400 500
300 10
900 900
300 10
50 900
50 900
700 900
500 900
50 10
20
896 546
543 216
454 310
408 367
40 602
252 582
954 627
850 234
763 479
232 278
301 538
528 508
936 154
629 443
758 336
432 700
882 256
278 738
517 882
317 136
20
410 610
831 909
675 629
421 774
386 869
544 219
492 414
996 557
499 482
231 285
804 978
304 881
489 911
75 315
927 648
252 914
330 396
937 133
495 882
813 717
sample output:
#1 150
#2 3000
#3 2370
#4 4721
#5 8231

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值