Description
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
HINT
50%的数据满足1≤D≤3。100%的数据满足1≤D≤9,1≤N, M≤10,-10000≤Vi≤10000。
这个题呀,好题。
可以边搜索边更新状态,用射线法(自己百度吧)。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
int n,m,d,ans,v[11],mp[11][11],x[11],y[11],dis[1105][11][11];
bool inq[1105][11][11];
int xx[]={-1,0,1,0},yy[]={0,-1,0,1};
struct node
{int x,y,z;//x,y坐标,z吃豆子的情况
};
queue<node>q;
void bfs(int sx,int sy)
{memset(dis,0x3f,sizeof(dis));memset(inq,0,sizeof(inq));node t;dis[0][sx][sy]=0;t.x=sx,t.y=sy,t.z=0;q.push(t);inq[0][sx][sy]=1;while(!q.empty()){node u=q.front();q.pop();inq[u.z][u.x][u.y]=0;for(int i=0;i<=3;i++)if(u.x+xx[i]>=1&&u.x+xx[i]<=n&&u.y+yy[i]>=1&&u.y+yy[i]<=m&&mp[u.x+xx[i]][u.y+yy[i]]==0){t.x=u.x+xx[i],t.y=u.y+yy[i],t.z=u.z;for(int j=1;j<=d;j++)if(t.y>y[j]&&((u.x>x[j]&&t.x<=x[j])||(u.x<=x[j]&&t.x>x[j])))//垂直于x轴的射线 t.z^=(1<<(j-1));if(dis[t.z][t.x][t.y]>dis[u.z][u.x][u.y]+1){dis[t.z][t.x][t.y]=dis[u.z][u.x][u.y]+1;if(!inq[t.z][t.x][t.y]){inq[t.z][t.x][t.y]=1;q.push(t);}}}}int end=(1<<d)-1;for(int i=1;i<=end;i++){int tmp=-dis[i][sx][sy];for(int j=1;j<=d;j++)if(i&(1<<(j-1)))tmp+=v[j];ans=max(tmp,ans);}
}
int main()
{scanf("%d%d%d",&n,&m,&d);for(int i=1;i<=d;i++)scanf("%d",&v[i]);for(int i=1;i<=n;i++){char s[15];scanf("%s",s+1);for(int j=1;j<=m;j++)if(s[j]=='#')mp[i][j]=1;else if(s[j]=='0')mp[i][j]=0;else{mp[i][j]=1;x[s[j]-'0']=i;y[s[j]-'0']=j;}}for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(mp[i][j]==0)bfs(i,j);printf("%d\n",ans);return 0;
}