应该算是比较裸的最短路和状压DP。。。感觉之前看到的题都是DP。。因为想的问题都一样。
有一点,由于状态在转移的时候,是由哪一个点转移过来的很重要,所以并不能通过取最小值来决定从哪一个点转移来,所以每个点产生的情况都要记录。在这里错了好久。。。
恩。。这样说来应该还是蛮简单的。。。。
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
#define maxn 211
#define maxdp 10110
#define inf 0x3f3f3f3f
int d[14][maxn][maxn];
int a[maxn][maxn];
int n,m,num,flag;
int vis[maxn][maxn];
int visdp[14][maxdp],dp[14][maxdp];
queue<pair<int,int>>que;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
class node
{
public:
int x,y;
int minn,cost;
}p[14];
bool check(int x,int y)
{
if(x<0||x>=n||y<0||y>=m) return false;
if(a[x][y]==inf) return false;
return true;
}
int min(int x,int y){return x<y?x:y;}
int max(int x,int y){return x>y?x:y;}
void SPFA()
{
memset(vis,0,sizeof(vis));
for(int i=0;i<num;i++)
{
int x=p[i].x,y=p[i].y;
d[i][x][y]=0;
que.push(make_pair(x,y));
vis[x][y]=1;
while(que.size())
{
x=que.front().first,y=que.front().second;
que.pop();
vis[x][y]=0;
for(int j=0;j<4;j++)
{
int tx=x+dx[j],ty=y+dy[j];
if(check(tx,ty))
if(d[i][x][y]+a[tx][ty]<d[i][tx][ty])
{
d[i][tx][ty]=d[i][x][y]+a[tx][ty];
if(!vis[tx][ty]) que.push(make_pair(tx,ty)),vis[tx][ty]=1;
}
}
}
p[i].minn=inf;
for(int j=0;j<m;j++)
p[i].minn=min(p[i].minn,min(d[i][0][j],d[i][n-1][j]));
for(int j=0;j<n;j++)
p[i].minn=min(p[i].minn,min(d[i][j][0],d[i][j][m-1]));
if(p[i].minn>=inf) {flag=1;break;}
}
}
void Tosoon()
{
for(int i=0;i<num;i++)
for(int j=0;j<maxdp;j++)
dp[i][j]=inf;
}
void Search()
{
memset(visdp,0,sizeof(visdp));
Tosoon();
int maxnum=(1<<num);
if(num==1)
{
int ans=p[0].minn*2+p[0].cost;
if(ans>=inf) cout<<0<<endl;
else cout<<ans<<endl;
return;
}
for(int i=0;i<maxnum;i++)
{
for(int j=0;j<num;j++)
{
int now=(1<<j)|i;
if(!i) dp[j][now]=p[j].minn+p[j].cost,visdp[j][now]=1;
else
{
int jj=1<<j;
if(i&jj) continue;
for(int k=0;k<num;k++)
{
if(!visdp[k][i]||d[k][p[j].x][p[j].y]>=inf) continue;
dp[j][now]=min(dp[j][now],dp[k][i]+d[k][p[j].x][p[j].y]);
visdp[j][now]=1;
}
}
}
}
int ans=inf;
for(int i=0;i<num;i++)
ans=min(ans,dp[i][maxnum-1]+p[i].minn);
if(ans>=inf) {cout<<0<<endl;return;}
cout<<ans<<endl;
}
void init()
{
for(int i=0;i<14;i++)
for(int j=0;j<maxn;j++)
for(int k=0;k<maxn;k++)
d[i][j][k]=inf;
}
int main()
{
int T;
cin>>T;
while(T--)
{
init();
flag=0;
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
cin>>a[i][j];
if(a[i][j]==-1) a[i][j]=inf;
}
cin>>num;
for(int i=0;i<num;i++)
{
cin>>p[i].x>>p[i].y;
p[i].cost=a[p[i].x][p[i].y];
if(p[i].cost==inf) flag=1;
}
SPFA();
if(flag){cout<<0<<endl;continue;}
Search();
}
return 0;
}