1294: [SCOI2009]围豆豆Bean
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 443 Solved: 299
[ Submit][ Status][ Discuss]
Description
![](http://www.lydsy.com/JudgeOnline/images/1294_1.jpg)
Input
第一行两个整数N和M,为矩阵的边长。 第二行一个整数D,为豆子的总个数。 第三行包含D个整数V1到VD,分别为每颗豆子的分值。 接着N行有一个N×M的字符矩阵来描述游戏矩阵状态,0表示空格,#表示障碍物。而数字1到9分别表示对应编号的豆子。
Output
仅包含一个整数,为最高可能获得的分值。
Sample Input
3 8
3
30 -100 30
00000000
010203#0
00000000
3
30 -100 30
00000000
010203#0
00000000
Sample Output
38
设F[I][J][S]表示可以走到(i,j),吃到集合数为S的最短步数,枚举起点BFS。用射线法判断是否围住。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 51210
int n,m,d,i,j,k,l,v[9],loc[9][2],S,ans,now;
int h,t,qx[N],qy[N],qk[N],f[11][11][513];
char a[12][12];
int cal(int px,int py,int x,int S){
for(int i=0;i<d;i++)
if(py<loc[i][1]&&(px==loc[i][0]&&x>loc[i][0]||px>loc[i][0]&&x==loc[i][0]))
S^=1<<i;
return S;
}
void add(int px,int py,int x,int y,int S,int w){
if(a[x][y]!='0')return;
S=cal(px,py,x,S);
if(~f[x][y][S])return;
f[x][y][S]=w;
qx[++t]=x,qy[t]=y,qk[t]=S;
}
void go(int x,int y,int S){
add(x,y,x-1,y,S,f[x][y][S]+1);
add(x,y,x+1,y,S,f[x][y][S]+1);
add(x,y,x,y-1,S,f[x][y][S]+1);
add(x,y,x,y+1,S,f[x][y][S]+1);
}
int main(){
scanf("%d%d%d",&n,&m,&d);
S=1<<d;
for(i=0;i<d;i++)scanf("%d",&v[i]);
for(i=0;i<=m+1;i++)a[0][i]=a[n+1][i]='#';
for(i=1;i<=n;i++)a[i][0]=a[i][m+1]='#';
for(i=1;i<=n;i++)for(scanf("%s",a[i]+1),j=1;j<=m;j++)
if(a[i][j]!='0'&&a[i][j]!='#')loc[a[i][j]-'1'][0]=i,loc[a[i][j]-'1'][1]=j;
for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(a[i][j]=='0'){
memset(f,-1,sizeof f);
f[i][j][0]=0;
qx[h=t=1]=i,qy[1]=j,qk[1]=0;
while(h<=t)go(qx[h],qy[h],qk[h]),h++;
for(k=0;k<S;k++)if(~f[i][j][k]){
for(now=l=0;l<d;l++)if((k>>l)&1)now+=v[l];
if(now-f[i][j][k]>ans)ans=now-f[i][j][k];
}
}
printf("%d",ans);
}