题目大意:有一个杀手,他一开始有一把枪,每次开枪只能造成一点伤害,他需要消灭n个敌人,每个敌人有各自的health[i], 并且有武器,消灭敌人就可以获得他的武器用来消灭其他敌人;
题目解析:n特别小,并且序列不需要有顺序,很明显是状态dp,dp[i]表示消灭序列i时所需要最少的开枪次数,然后dp的时候枚举没有消灭的敌人,选择消灭过的敌人们的武器与自己的作比较,这样肯定是最优解,然后dp就可以转移了;
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#define inf 0x3ffffff
using namespace std;
int dp[(1<<15)+10],health[20],gun[20][20];
int main()
{
int cas,cnt=1,i,j,k,len,n,ma;
string s;
scanf("%d",&cas);
while(cas--)
{
cin>>n;
for(i=0;i<n;i++)
{
scanf("%d",&health[i]);
}
for(i=0;i<n;i++)
{
cin>>s;
for(j=0;j<n;j++)
{
gun[i][j]=s[j]-'0';
}
}
len=1<<n;
for(i=0;i<len;i++)
dp[i]=inf;
dp[0]=0;
for(i=0;i<n;i++)
{
dp[1<<i]=health[i];
}
for(i=0;i<len;i++)
{
for(j=0;j<n;j++)
{
if((i&(1<<j))==0)
{
ma=1;
for(k=0;k<n;k++)
{
if(i&(1<<k))
{
ma=max(ma,gun[k][j]);
}
}
if(health[j]%ma==0)
dp[i|(1<<j)]=min(dp[i|(1<<j)],dp[i]+health[j]/ma);
else
dp[i|(1<<j)]=min(dp[i|(1<<j)],dp[i]+health[j]/ma+1);
}
}
}
printf("Case %d: %d\n",cnt++,dp[len-1]);
}
return 0;
}