转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
http://acm.fzu.edu.cn/problem.php?pid=2073
又是一个神题,给出一个n*m的图,上面有若干个怪,每个怪有一定的血,攻击,防御,以及攻击奖励,防御奖励。玩过魔塔的童鞋应该很清楚,每打一个怪,消灭他,可以获得一定的攻击防御奖励,消灭所有的怪,就算成功了。
此题是外挂摸式,无限血,不过也存在无法过关的情况,求消灭所有的怪,受到的最少伤害。
想当年cxlove通关救出了公主,哈哈。
处理起来很麻烦,首先枚举所有的怪为起点,bfs找可以到达的其它怪,邻接阵保存。
之后是状态DP,dp[i][j],表示当前位置为i,当前状态为j。
/*
ID:cxlove
PROB:FJU2073魔塔
DATA:2012.3.27-3.28
HINT:bfs+状态DP
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define inf 1<<30
using namespacestd;
struct Node{
inthp,attack,defense,award_attack,award_defense;
//怪的血量,攻击,防御,攻击奖励,防御奖励
}monster[11];
struct Point{
int x,y;
}s,que[500*500+10];
struct Monster{
Point pos;
int kind;
//记录地图上怪兽的位置和怪物种类
}Map[11];
char str[505][505];
int cnt;//怪兽的个数
int n,m,p;
int mat[15][15];
bool flag[505][505];
int way[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int dp[11][1<<10]; //dp[i][j]表示目前处在第i个怪物的位置,已杀怪物的状态为j时的最少伤害
void bfs(int k){
Point p;
inthead=0,tail=0;
que[tail++]=Map[k].pos;
flag[que[0].x][que[0].y]=true;
while(head<tail){
p=que[head++];
for(int i=0;i<4;i++){
Point pp;
pp.x=p.x+way[i][0];
pp.y=p.y+way[i][1];
if(str[pp.x][pp.y]!='*'&&pp.x>=0&&pp.x<n&&pp.y>=0&&pp.y<m&&flag[pp.x][pp.y]==false){
if(str[pp.x][pp.y]=='.')
que[tail++]=pp;
else{
for(int j=1;j<=cnt;j++)
if(pp.x==Map[j].pos.x&&pp.y==Map[j].pos.y)
mat[k][j]=1;
}
flag[pp.x][pp.y]=true;
}
}
}
}
int check(int state,int k){
intper_attack=10,per_deffense=10;
//初始攻击,防御
for(int i=0;i<cnt;i++)
if((1<<i)&state){
intkind=Map[i+1].kind;
per_attack=min(50,monster[kind].award_attack+per_attack);
per_deffense=min(50,monster[kind].award_defense+per_deffense);
}
intkind=Map[k].kind;
/*cout<<per_attack<<""<<per_deffense<<endl;*/
if(per_attack<=monster[kind].defense)
return-1;
if(per_deffense>=monster[kind].attack)
return0;
inthp=monster[kind].hp,a1=per_attack,d1=monster[kind].defense,a2=monster[kind].attack,d2=per_deffense;
return(hp/(a1-d1)+(hp%(a1-d1)==0?-1:0))*(a2-d2);
}
int sum[1<<10];
vector<int>status[11];
int main(){
sum[0]=0;
for(int i=1;i<(1<<10);i++){
sum[i]=sum[i>>1]+(i&1);
status[sum[i]].push_back(i);
}
while(scanf("%d%d%d",&n,&m,&p)!=EOF){
cnt=0;
for(int i=1;i<=p;i++)
scanf("%d%d%d%d%d",&monster[i].hp,&monster[i].attack,&monster[i].defense,&monster[i].award_attack,&monster[i].award_defense);
for(int i=0;i<n;i++){
scanf("%s",str[i]);
for(int j=0;j<m;j++)
if(str[i][j]=='#'){
s.x=i;
s.y=j;
}
elseif(str[i][j]>='1'&&str[i][j]<='9'){
cnt++;
Map[cnt].pos.x=i;
Map[cnt].pos.y=j;
Map[cnt].kind=str[i][j]-'0';
}
}
Map[0].pos=s;Map[0].kind=0;
memset(mat,0,sizeof(mat));
for(int i=0;i<=cnt;i++){
memset(flag,false,sizeof(flag));
bfs(i);
}
/*for(inti=0;i<=cnt;i++){
for(int j=0;j<=cnt;j++)
printf("%d ",mat[i][j]);
printf("\n");
}*/
for(int i=0;i<=cnt;i++)
for(int j=0;j<(1<<cnt);j++)
dp[i][j]=inf;
dp[0][0]=0;
for(int i=1;i<=cnt;i++){
if(mat[0][i]){
inttemp=check(0,i);
if(temp<0)
continue;
dp[i][1<<(i-1)]=temp;
}
}
/*for(inti=1;i<=cnt;i++)
if(dp[i][1<<(i-1)]!=inf)
printf("%d%d\n",i,dp[i][1<<(i-1)]);*/
for(int i=1;i<cnt;i++){
for(int j=0;j<status[i].size();j++){
intJ=status[i][j];
for(int k=1;k<=cnt;k++){
//dp[k][J]
if(((1<<(k-1))&J)&&dp[k][J]!=inf){
for(int r=1;r<=cnt;r++){
if(mat[k][r]&&k!=r&&((1<<(r-1))&J)==0){
int temp=check(J,r);
/*cout<<k<<" "<<J<<""<<r<<" "<<temp<<endl;
system("pause");*/
if(temp<0)
continue;
dp[r][J|(1<<(r-1))]=min(dp[r][J|(1<<(r-1))],dp[k][J]+temp);
for(intrr=1;rr<=cnt;rr++)//注意!!!BFS的时候状态是在原图未消灭一个怪的前提下,注意更新后的情况
if(J&(1<<(rr-1)))
dp[rr][J|(1<<(r-1))]=min(dp[rr][J|(1<<(r-1))],dp[r][J|(1<<(r-1))]);
}
}
}
}
}
}
int ans=inf;
for(int i=1;i<=cnt;i++)
ans=min(ans,dp[i][(1<<cnt)-1]);
if(ans==inf)
printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}
/*
1313 6
1012 2 2 1
202 2 2 3
3013 3 1 1
4014 4 1 1
5011 5 1 1
6028 6 1 1
*************
*..121......*
***********.*
*.....*...*.*
*.5.*.*...*.*
**.**.***.*.*
*...*..343*.*
*.6.*.*****.*
**.**.......*
*...**.***.**
*...*...*.3.*
*...*.#.*1..*
*************
513 2
1012 2 2 1
202 2 2 3
*************
*..121......*
***********.*
*...#.*...*.*
*************
*/