CodeForces - 6D Lizards and Basements 2 (dfs + 回溯)
阿新 • • 發佈:2020-09-18
題目大意:
有一隊人,你可以用火球點某個人,會對當前人造成\(a\)點傷害,對旁邊的人造成\(b\)點傷害。
不能打\(1\)號和\(n\)號,求最少多少發點死所有人。
輸出最少次數和每次選擇攻擊的人的序列。
思路:
看資料範圍容易想到暴力\(dfs\),由於\(1\)號點不能打,我們考慮從\(2\)號點開始\(dfs\),直到\(n-1\)號點。
設\(dfs(x, sum)\)為前\(x\)個敵人至少需要攻擊\(sum\)次。
注意判斷是否能打掉最左邊和最右邊的敵人。
Code:
#include <bits/stdc++.h> using namespace std; const int N = 15; const int INF = 0x3f3f3f3f; int h[N], n, a, b, ans = INF; vector<int> tmp, seq; void dfs(int x, int sum) { //dfs(x, sum)表示打掉前x個弓箭手最少需要打sum發 if (sum >= ans) return; //最優性剪枝 if (x == n) { //搜尋結束 if (h[n] < 0) { //如果能把最右邊的打掉則可更新答案 ans = sum; seq = tmp; } return; } for (int i = 0; i <= max({h[x - 1] / b, h[x] / a, h[x + 1] / b}) + 1; i++) { //列舉攻擊次數 if (h[x - 1] - b * i < 0) { //如果能打掉最左邊 h[x - 1] -= b * i; h[x] -= a * i; h[x + 1] -= b * i; for (int j = 0; j < i; j++) { //按攻擊次數加入到被攻擊敵人序列中 tmp.push_back(x); } dfs(x + 1, sum + i); //繼續往後搜 h[x - 1] += b * i; //回溯 h[x] += a * i; h[x + 1] += b * i; for (int j = 0; j < i; j++) { //從序列中彈出 tmp.pop_back(); } } } } int main() { cin >> n >> a >> b; for (int i = 1;i <= n; i++) cin >> h[i]; dfs(2, 0); cout << ans << endl; for (auto i : seq) cout << i << " "; cout << endl; return 0; }