福大3月月赛 魔塔

转载请注明出处,谢谢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......*
***********.*
*...#.*...*.*
*************
*/



你可能感兴趣的:(struct,System,ini,HP)