dfs——Lizards and Basements 2

Lizards and Basements 2

题面翻译

题意

有一队人,你可以用火球点某个人,会对当前人造成a点伤害,对旁边的人造成b点伤害。

不能打1号和n号,求最少多少发点死所有人。

题目描述

This is simplified version of the problem used on the original contest. The original problem seems to have too difiicult solution. The constraints for input data have been reduced.

Polycarp likes to play computer role-playing game «Lizards and Basements». At the moment he is playing it as a magician. At one of the last levels he has to fight the line of archers. The only spell with which he can damage them is a fire ball. If Polycarp hits the $ i $ -th archer with his fire ball (they are numbered from left to right), the archer loses $ a $ health points. At the same time the spell damages the archers adjacent to the $ i $ -th (if any) — they lose $ b $ ( $ 1<=b<a<=10 $ ) health points each.

As the extreme archers (i.e. archers numbered 1 and $ n $ ) are very far, the fire ball cannot reach them. Polycarp can hit any other archer with his fire ball.

The amount of health points for each archer is known. An archer will be killed when this amount is less than 0. What is the minimum amount of spells Polycarp can use to kill all the enemies?

Polycarp can throw his fire ball into an archer if the latter is already killed.

输入格式

The first line of the input contains three integers $ n,a,b $ ( $ 3<=n<=10 $ ; $ 1<=b<a<=10 $ ). The second line contains a sequence of $ n $ integers — $ h_{1},h_{2},…,h_{n} $ ( $ 1<=h_{i}<=15 $ ), where $ h_{i} $ is the amount of health points the $ i $ -th archer has.

输出格式

In the first line print $ t $ — the required minimum amount of fire balls.

In the second line print $ t $ numbers — indexes of the archers that Polycarp should hit to kill all the archers in $ t $ shots. All these numbers should be between 2 and $ n-1 $ . Separate numbers with spaces. If there are several solutions, output any of them. Print numbers in any order.

样例 #1

样例输入 #1

3 2 1
2 2 2

样例输出 #1

3
2 2 2

样例 #2

样例输入 #2

4 3 1
1 4 1 1

样例输出 #2

4
2 2 3 3

思路

这道题如果单纯暴力搜索的话(我们此时是按答案的长度为迭代的次数(也就是暴力枚举答案的某个位数填的是什么数字)),会卡在# 43。(见我代码注释掉的代码)

为什么会卡住呢?因为当w[i]比较大,但a,b比较小的时候,那么这个时候我们的搜索次数就会大大增加,因此就会超时。

因此,对于一次一次减超时的情况,我们可以采取一次减非常多(我们直接按顺序减,为什么呢?因为每个w[i]减去的次数是有限的,而且w[i]<15,所以次数不怎么多),此时我们只需在dfs的参数上新增一个k,用来记录上一次减的是哪个数字。也就是如图:
在这里插入图片描述
但我们还得注意的是:我刚开始写的时候是每遍历完都要判断是否血量小于0,这个太耗时了,因此我们采取:
在这里插入图片描述
具体参考

代码(卡#21)

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>

using namespace std;

const int N = 20;

int w[N];
bool st[N];
int pre[N],c[N];
int n, a, b;
int ans = 2e9;

void dfs(int u) {

	if (ans <= u) {
		return;
	}

	bool f = false;
	for (int i = 1; i <= n; i++) {
		if (w[i] >= 0) {
			f = true;
			break;
		}
	}

	if (!f) {
		if (ans >= u) {
			ans = u;
			for (int i = 1; i <= ans; i++) {
				pre[i] = c[i];
			}
		}
		return;
	}

	for (int i = 2; i < n; i++) {
		if (w[i] < 0 && w[i - 1] < 0 && w[i + 1] < 0)continue;
		w[i] -= a, w[i - 1] -= b, w[i + 1] -= b;
		c[u+1] = i;
		dfs(u + 1);
		w[i] += a, w[i - 1] += b, w[i + 1] += b;
	}

}

int main() {

	cin >> n >> a >> b;

	for (int i = 1; i <= n; i++) {
		cin >> w[i];
	}

	dfs(1);

	cout << ans-1 << endl;

	for (int i = 2; i <= ans; i++) {
		cout << pre[i] << " ";
	}

	return 0;

}

代码(卡#43)

//我们可以让dfs的参数为答案的第几位

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 110;

int w[N];
int n,a,b;
int c[N],pre[N];
int ans=2e9;

void dfs(int u,int start){
    if(u>=ans){
        return;
    }
    
    bool f=false;
    for(int i=1;i<=n;i++){
        if(w[i]>=0){
            f=true;
            break;
        }
    }
    
    if(!f){
        ans=min(ans,u);
        for(int i=0;i<ans;i++){
            pre[i]=c[i];
        }
    }
    
    for(int i=start;i<n;i++){
        if(w[i]<0&&w[i-1]<0&&w[i+1]<0)continue;
        w[i]-=a;
        w[i-1]-=b,w[i+1]-=b;
        c[u]=i;
        dfs(u+1,i);
        w[i]+=a;
        w[i-1]+=b,w[i+1]+=b;
    }
}

int main(){
    cin>>n>>a>>b;
    
    for(int i=1;i<=n;i++){
        cin>>w[i];
    }
    
    dfs(0,2);
    
    cout<<ans<<endl;
    
    for(int i=0;i<ans;i++){
        cout<<pre[i]<<' ';
    }
    return 0;
}

代码(100分)

//我们可以让dfs的参数为答案的第几位

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 110;

int w[N];
int n,a,b;
int c[N],pre[N];
int ans=2e9;

void dfs(int u,int start,int k){
    if(u>=ans){
        return;
    }
    
    // bool f=false;
    // for(int i=1;i<=n;i++){
    //     if(w[i]>=0){
    //         f=true;
    //         break;
    //     }
    // }
    
    // if(!f){
    //     ans=min(ans,u);
    //     for(int i=0;i<ans;i++){
    //         pre[i]=c[i];
    //     }
    // }
    
    if(k>=n){
        if(w[k]>=0||w[n]>=0)return;
        ans=min(ans,u);
        for(int i=0;i<ans;i++){
            pre[i]=c[i];
        }
        return;
    }
    
    //单纯这样写会超时,为什么呢?因为你当a很小但你的值很大,减的次数就很多,因此我们就模拟减的过程即可
    // for(int i=start;i<n;i++){
    //     if(w[i]<0&&w[i-1]<0&&w[i+1]<0)continue;
    //     w[i]-=a;
    //     w[i-1]-=b,w[i+1]-=b;
    //     c[u]=i;
    //     dfs(u+1,i);
    //     w[i]+=a;
    //     w[i-1]+=b,w[i+1]+=b;
    // }
    
    for(int i=0;i<=max(w[k]/a+1,max(w[k-1]/b+1,w[k+1]/b+1));i++){
        if(w[k-1]-i*b>=0)continue;
        w[k]-=i*a;
        w[k-1]-=i*b,w[k+1]-=i*b;
        for(int j=u;j<=u+i;j++)c[j]=k;
        dfs(u+i,i,k+1);
        w[k]+=i*a;
        w[k-1]+=i*b,w[k+1]+=i*b;
    }
}

int main(){
    cin>>n>>a>>b;
    
    for(int i=1;i<=n;i++){
        cin>>w[i];
    }
    
    dfs(0,2,2);
    
    cout<<ans<<endl;
    
    for(int i=0;i<ans;i++){
        cout<<pre[i]<<' ';
    }
    return 0;
}
  • 26
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

green qwq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值