轉載請註明出處,謝謝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:cxlovePROB:FJU2073魔塔DATA:2012.3.27-3.28HINT:bfs+狀態DP*/#include<iostream>#include<cstdio>#include<cstring>#include<vector>#define inf 1<<30using 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 61012 2 2 1202 2 2 33013 3 1 14014 4 1 15011 5 1 16028 6 1 1**************..121......************.**.....*...*.**.5.*.*...*.***.**.***.*.**...*..343*.**.6.*.*****.***.**.......**...**.***.***...*...*.3.**...*.#.*1..**************513 21012 2 2 1202 2 2 3**************..121......************.**...#.*...*.***************/