题意:有n个怪物,一次能打3个相邻的怪物,怪物都是连成一圈的,每次打完3个怪物后,其余怪物都会来攻击,给出n个怪物的攻击值,求消灭所有怪物所需受的最小攻击值。
分析:状压dp, dp[i]表示在i这种状态下(i 的二进制形式表示状态),怪物对主角的最小攻击值。sum[j]初始化,便于计算在j状态下的所剩怪物的伤害值总和,遍历一下状态即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <limits.h>
using namespace std;
typedef long long ll;
const int maxn=10000000;
int num[30],dp[1<<21],sum[1<<21];
int main()
{
int n;
memset(num,0,sizeof(num));
memset(dp,maxn,sizeof(dp));
memset(sum,0,sizeof(sum));
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)
scanf("%d",&num[i]);
for(int i=1; i<= (1<<n)-1; i++)
{
for(int j=0; j<n; j++)
if(i&(1<<j))
sum[i]+=num[j];
}
dp[(1<<n)-1]=0;//全1就是初始状态,怪物都还在,伤害值为0
for(int i=(1<<n)-1; i>=1; i--)
{
for(int j=0;j<n;j++)
{
if(i&(1<<j))//如果i种状态下第j个怪物还没有被消灭
{
int j1,j2,x=i-(1<<j);//消灭第j的怪物
if(j==0)//同时也消灭j前后的
j1=n-1;
else
j1=j-1;
if(j==n-1)
j2=0;//第一个
else
j2=j+1;
if(x&(1<<j1))
x-=(1<<j1);
if(x&(1<<j2))
x-=(1<<j2);//计算出所剩余的怪物造成的杀伤力
dp[x]=min(dp[x],dp[i]+sum[x]);//x这种状态是从i种状态转移过来的
}
}
}
printf("%d\n",dp[0]);
}
return 0;
}