题目大意,一个格子你走进去有一个花费,也可能不能走那个格子,每次只能上下左右的移动,花费和能不能走都会用一个矩阵表示好告诉你。
有的格子是一个宝藏,你可以从边界外进入边界的任意一个点,出发找宝藏,最后回到边界外,在获得尽可能多的宝藏的前提下,走最小花费。
所以队友敲的时候说,先把13个宝藏对边界求最短距离,再求13个宝藏之间的最短距离,然后对于站在哪个宝藏的位置上遍历过哪些宝藏,做一个状压。
我敲BFS他敲(一维)状压。
ps: 因为可能出现宝藏被不可达的路分割成独立的两大块等坑爹情况,做的时候要注意前提——获得尽可能多的宝藏,以及走最小花费。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
int d[14][14];
int g[222][222];
int N,M,K;
struct Node{
int x,y,d;
Node(int x=0,int y=0,int d=0):x(x),y(y),d(d){}
bool operator <(const Node &rhs)const{
return d>rhs.d;
}
}pnt[14];
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
int vis[222][222];
void bfs(int id){
memset(vis,-1,sizeof vis);
Node o = Node(pnt[id].x,pnt[id].y,0),nx;
priority_queue<Node>q;
q.push(o);
int tot=N*M,cnt=0;
while(!q.empty() && cnt<tot){
o = q.top();
q.pop();
if(-1 != vis[o.x][o.y]) continue;
vis[o.x][o.y] = o.d;
cnt++;
for(int i=0;i<4;i++){
nx=o;
nx.x+=dx[i];
nx.y+=dy[i];
if(nx.x<0 || nx.x>=N || nx.y<0 || nx.y>=M || g[nx.x][nx.y]==-1) continue;
nx.d+=g[nx.x][nx.y];
q.push(nx);
}
}
for(int i=1;i<=K;i++){
if(d[id][i] < vis[pnt[i].x][pnt[i].y])
d[id][i] = vis[pnt[i].x][pnt[i].y];
}
int *p = &d[id][0];
for(int i=0;i<N;i++){
if(vis[i][0]!=-1)
if(*p==-1 || *p > vis[i][0]) *p=vis[i][0];
if(vis[i][M-1]!=-1)
if(*p==-1 || *p > vis[i][M-1]) *p=vis[i][M-1];
}
for(int i=0;i<M;i++){
if(vis[0][i]!=-1)
if(*p==-1 || *p > vis[0][i]) *p=vis[0][i];
if(vis[N-1][i]!=-1)
if(*p==-1 || *p > vis[N-1][i]) *p=vis[N-1][i];
}
}
int dp[14][1<<14];
void go()
{
memset(dp,0,sizeof dp);
for(int i=1;i<=K;i++)
if(d[i][0]!=-1&&g[pnt[i].x][pnt[i].y]!=-1)
dp[i][1<<(i-1)]=d[i][0]+g[pnt[i].x][pnt[i].y];
for(int s=1;s<(1<<K);s++)
for(int i=1;i<=K;i++)
if(dp[i][s])
for(int j=1;j<=K;j++)
if(((1<<(j-1))&s)==0&&d[i][j]!=-1)
if(dp[j][s+(1<<(j-1))]==0||dp[j][s+(1<<(j-1))]>dp[i][s]+d[i][j])
dp[j][s+(1<<(j-1))]=dp[i][s]+d[i][j];
int ans1=0,ans=0;
for(int s=1;s<(1<<K);s++)
for(int i=1;i<=K;i++)
if(dp[i][s])
{
int tot=0;
for(int j=1;j<=K;j++)
if(((1<<(j-1))&s))tot++;
if(tot==ans1)ans=min(ans,dp[i][s]+d[i][0]);
if(tot>ans1)ans1=tot,ans=dp[i][s]+d[i][0];
}
printf("%d\n",ans);
}
int main()
{
//freopen("data.in","r",stdin);
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&N,&M);
for(int i=0;i<N;i++)
for(int j=0;j<M;j++)
scanf("%d",&g[i][j]);
scanf("%d",&K);
for(int i=1;i<=K;i++)
scanf("%d%d",&pnt[i].x,&pnt[i].y);
memset(d,-1,sizeof d);
for(int i=1;i<=K;i++)
{
bfs(i);
// printf("11 %d %d\n",i,d[i][0]+g[pnt[i].x][pnt[i].y]);
}
//puts("o")
go();
}
return 0;
}