cogs 1816. [SCOI2009]围豆豆

  1. [SCOI2009]围豆豆
    ★★★ 输入文件:bean.in 输出文件:bean.out 简单对比
    时间限制:1 s 内存限制:256 MB
    【题目描述】

是不是平时在手机里玩吃豆豆游戏玩腻了呢?最近MOKIA手机上推出了一种新的围豆豆游戏,大家一起来试一试吧。
游戏的规则非常简单,在一个N×M的矩阵方格内分布着D颗豆子,每颗豆有不同的分值Vi。游戏者可以选择任意一个方格作为起始格,每次移动可以随意的走到相邻的四个格子,直到最终又回到起始格。最终游戏者的得分为所有被路径围住的豆豆的分值总和减去游戏者移动的步数。矩阵中某些格子内设有障碍物,任何时刻游戏者不能进入包含障碍物或豆子的格子。游戏者可能的最低得分为0,即什么都不做。
注意路径包围的概念,即某一颗豆在路径所形成的多边形(可能是含自交的复杂多边形)的内部。下面有两个例子:

第一个例子中,豆在路径围成的矩形内部,所以豆被围住了。第二个例子中,虽然路径经过了豆的周围的8个格子,但是路径形成的多边形内部并不包含豆,所以没有围住豆子。
布布最近迷上了这款游戏,但是怎么玩都拿不了高分。聪明的你决定写一个程序来帮助他顺利通关。
【输入格式】

输入文件bean.in第一行两个整数N和M,为矩阵的边长。
第二行一个整数D,为豆子的总个数。
第三行包含D个整数V1到VD,分别为每颗豆子的分值。
接着N行有一个N×M的字符矩阵来描述游戏矩阵状态,0表示空格,#表示障碍物。而数字1到9分别表示对应编号的豆子。
【输出格式】

输出文件bean.out仅包含一个整数,为最高可能获得的分值。
【样例输入】

3 8
3
30 -100 30
00000000
010203#0
00000000
【样例输出】

38
【提示】

50%的数据满足1≤D≤3。
100%的数据满足1≤D≤9,1≤N, M≤10,-10000≤Vi≤10000。
【来源】

四川OI 2009


【分析】
好题好题


【代码】

//SCOI 围豆豆 
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=105;
int n,m,d,ans;
char ch[15];
bool vis[15][15][1<<9];
int dx[4]={0,0,-1,1},dy[4]={1,-1,0,0},dis[15][15][1<<9]; 
int score[10],map[15][15],whe[15][2];
struct node {int x,y,p;};
queue <node> q;
inline void spfa(int sx,int sy)
{
    int i,j,k,p;
    memset(dis,0x3f,sizeof dis);
    dis[sx][sy][0]=0;
    q.push((node){sx,sy,0});
    vis[sx][sy][0]=1;
    while(!q.empty())
    {
        node u=q.front();
        q.pop();
        vis[u.x][u.y][u.p]=0;
        fo(i,0,3)
        {
            int tx=u.x+dx[i],ty=u.y+dy[i];
            if(tx>=1 && tx<=n && ty>=1 && ty<=m && !map[tx][ty])
            {
                int now=u.p;
                fo(k,1,d)
                {
                    int nex=whe[k][0],ney=whe[k][1];
                    if(tx<nex && ((u.y==ney&&ty>ney)||(u.y>ney&&ty==ney)))
                      now^=(1<<(k-1));
                }
                if(dis[tx][ty][now]>dis[u.x][u.y][u.p]+1)
                {
                    dis[tx][ty][now]=dis[u.x][u.y][u.p]+1;
                    if(!vis[tx][ty][now])
                      vis[tx][ty][now]=1,q.push((node){tx,ty,now});
                }
            }
        }
    }
    fo(p,0,(1<<d)-1)
    {
        int sum=0;
        fo(i,1,d) if((1<<(i-1))&p) sum+=score[i];
        ans=max(ans,sum-dis[sx][sy][p]);
    }
}
int main()
{
    freopen("bean.in","r",stdin);
    freopen("bean.out","w",stdout);
    int i,j,k;
    scanf("%d%d%d",&n,&m,&d);
    fo(i,1,d) scanf("%d",&score[i]);
    fo(i,1,n)
    {
        scanf("%s",ch+1);
        fo(j,1,m)
        {
            if(ch[j]=='#') map[i][j]=-1;
            else map[i][j]=ch[j]-'0';
            if(map[i][j]>=1) whe[map[i][j]][0]=i,whe[map[i][j]][1]=j;
        }
    }
    fo(i,1,n)
      fo(j,1,m)
        if(!map[i][j])
          spfa(i,j);
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值