首页 > 代码库 > Circling Round Treasures(codeforces 375c)

Circling Round Treasures(codeforces 375c)

题意:要求在一张网格图上走出一条闭合路径,不得将炸弹包围进去,使围出的总价值减去路径长度最大。

/*
  类似于poj3182的做法,只不过出现了多个点,那么就用状态压缩的方法记录一个集合即可。 
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
char map[25][25],ch[25];
int n,m,sx,sy,tx,ty,nx,ny,gx[10],gy[10],val[10],w[1010],dp[25][25][1010],cnt=-1,ans;
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
struct node{int x,y,k;};
bool ok(int j){
    if(nx==gx[j]&&ny<gy[j]){
        if(nx>tx)return true;
    }
    else if(tx==gx[j]&&ty<gy[j]){
        if(tx>nx)return true;
    }
    return false;
}
void bfs(){
    memset(dp,-1,sizeof(dp));
    queue<node> q;
    node u;u.x=sx;u.y=sy;u.k=0;q.push(u);dp[sx][sy][0]=0;
    while(!q.empty()){
        u=q.front();q.pop();nx=u.x;ny=u.y;int nk=u.k,tk;
        if(nx==sx&&ny==sy)ans=max(ans,w[nk]-dp[nx][ny][nk]);
        for(int i=0;i<4;i++){
            tx=nx+dx[i];ty=ny+dy[i];tk=nk;
            if(tx<1||tx>n||ty<1||ty>m||(map[tx][ty]!=.&&map[tx][ty]!=S))continue;
            for(int j=0;j<=cnt;j++)
                if(ok(j))tk^=(1<<j);
            if(dp[tx][ty][tk]==-1){
                dp[tx][ty][tk]=dp[nx][ny][nk]+1;
                node v;v.x=tx;v.y=ty;v.k=tk;q.push(v);
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",ch);
        for(int j=1;j<=m;j++){
            map[i][j]=ch[j-1];
            if(map[i][j]==S)sx=i,sy=j;
            if(map[i][j]>=1&&map[i][j]<=8){
                int t=map[i][j]-1;++cnt;
                gx[t]=i;gy[t]=j;
            }
        }
    }
    for(int i=0;i<=cnt;i++)scanf("%d",&val[i]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(map[i][j]==B){
                ++cnt;gx[cnt]=i;gy[cnt]=j;val[cnt]=-10000;
            }
    for(int i=0;i<(1<<cnt+1);i++)
        for(int j=0;j<=cnt;j++)
            if(i&(1<<j))w[i]+=val[j];
    bfs();
    printf("%d",ans);
    return 0;
}

 

Circling Round Treasures(codeforces 375c)