False Mirrors URAL 1152.
题目大意:这道题的大体意思是,一个n个阳台,每个阳台上有多个怪物,a1,a2,a3……an; 然后一个人可以shoot,射中一个阳台,那么这个阳台和左右两边相邻的阳台上的怪物都会死掉,剩下的不死的怪物就会反击,每只反击一个Unit的伤害,问最小的伤害是多少? a1和an是相邻的! 假如a1和a 5之间阳台都被毁坏了,也不算数相邻的!
input:
7
3 4 2 2 1 4 1
output:
9
先射击4,受到的伤害2+1+4+1=8;再射击1,受到伤害1。总共8+1=9;
题目分析:直接dfs搜最优解。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 10;
const int inf = 0x3f3f3f3f;
int data[maxn], Max;
int n;
bool vis[maxn];
void dfs(int sum, int damage)
{
// printf("%d\n", sum);
if(sum == 0)
{
Max = min(damage, Max);
return ;
}
if(damage > Max) return ;
for(int i = 0; i < n; i++)
{
int Front = (i == 0 ? n - 1 : i - 1);
int Back = (i == n - 1 ? 0 : i + 1);
int v = sum - data[i] - data[Front] - data[Back];
if(data[i] + data[Front] + data[Back])
{
int td = damage + v;
int c = data[i], c1 = data[Front], c2 = data[Back];
data[i] = data[Front] = data[Back] = 0;
dfs(v, td);
data[i] = c;
data[Front] = c1;
data[Back] = c2;
}
}
}
int main()
{
int sum = 0;
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%d", &data[i]);
sum += data[i];
}
Max = inf;
dfs(sum, 0);
printf("%d\n", Max);
}
后来看了梁同学的做法,发现可以状压记录状态+DFS,这样比单纯的DFS快很多。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 10;
const int inf = 0x3f3f3f3f;
int data[maxn], n, dp[1 << 21];
int dfs(int now)
{
if(!now) return 0;
if(dp[now] != inf) return dp[now];
for(int i = 0; i < n; i++) {
if(!(now & (1 << i))) continue;
int nextnow = now;
int Front = (i == 0 ? n - 1 : i - 1);
int Back = (i == n - 1 ? 0 : i + 1);
nextnow = (nextnow & (~(1 << i)));
nextnow = (nextnow & (~(1 << Front)));
nextnow = (nextnow & (~(1 << Back)));
int hurt = 0;
for(int j = 0; j < n; j++)
{
if(nextnow & (1 << j)) hurt += data[j];
}
dp[now] = min(dfs(nextnow) + hurt, dp[now]);
}
return dp[now];
}
int main()
{
memset(dp, inf, sizeof(dp));
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%d", &data[i]);
printf("%d\n", dfs((1 << n) - 1));
}