题目链接
2 3 3 3 2 3 5 4 3 1 4 2 1 1 1 3 3 3 2 3 5 4 3 1 4 2 2 1 1 2 2
8 11
#include<stdio.h> #include<queue> #include<string.h> #include<algorithm> #define nn 220 #define inff 0x3f3f3f using namespace std; int a[nn][nn],n,m,K; int id[nn][nn],ma[15][15]; int p[nn*nn],num; struct node { int en,next,len; }E[nn*nn*5]; void init() { num=0; memset(p,-1,sizeof(p)); } void add(int st,int en,int len) { E[num].en=en; E[num].len=len; E[num].next=p[st]; p[st]=num++; } int dis[nn*nn]; bool vis[nn*nn]; struct Node { int id,val; friend bool operator<(Node x,Node y) { return x.val>y.val; } }sta,tem; void dij(int st) { priority_queue<Node> que; int i; for(i=0;i<nn*nn;i++) dis[i]=inff,vis[i]=false; dis[st]=0; tem.id=st,tem.val=0; que.push(tem); while(que.size()) { sta=que.top(); que.pop(); if(dis[sta.id]<sta.val) continue; for(i=p[sta.id];i+1;i=E[i].next) { int w=E[i].en; if(dis[w]>dis[sta.id]+E[i].len) { dis[w]=dis[sta.id]+E[i].len; tem.id=w,tem.val=dis[w]; que.push(tem); } } } } int x[15],y[15]; int dp[9000][15]; int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); int k=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) id[i][j]=++k; init(); for(int i=1;i<=n;i++) { if(a[i][1]!=-1) { add(0,id[i][1],a[i][1]); add(id[i][1],0,0); } if(a[i][m]!=-1) { add(0,id[i][m],a[i][m]); add(id[i][m],0,0); } } for(int j=2;j<m;j++) { if(a[1][j]!=-1) { add(0,id[1][j],a[1][j]); add(id[1][j],0,0); } if(a[n][j]!=-1) { add(0,id[n][j],a[n][j]); add(id[n][j],0,0); } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(a[i][j]==-1) continue; if(j>1&&a[i][j-1]!=-1) add(id[i][j],id[i][j-1],a[i][j-1]); if(j<m&&a[i][j+1]!=-1) add(id[i][j],id[i][j+1],a[i][j+1]); if(i>1&&a[i-1][j]!=-1) add(id[i][j],id[i-1][j],a[i-1][j]); if(i<n&&a[i+1][j]!=-1) add(id[i][j],id[i+1][j],a[i+1][j]); } } dij(0); scanf("%d",&K); for(int i=0;i<=K;i++) for(int j=0;j<=K;j++) ma[i][j]=inff; for(int i=1;i<=K;i++) { scanf("%d%d",&x[i],&y[i]); x[i]++,y[i]++; } for(int i=1;i<=K;i++) ma[0][i]=dis[id[x[i]][y[i]]]; for(int i=1;i<=K;i++) { dij(id[x[i]][y[i]]); ma[i][0]=dis[0]; for(int j=1;j<=K;j++) { ma[i][j]=dis[id[x[j]][y[j]]]; } } init();///重新建图是因为超级起点会影响点与点直接的距离(只是我这个本方法有会影响) for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(a[i][j]==-1) continue; if(j>1&&a[i][j-1]!=-1) add(id[i][j],id[i][j-1],a[i][j-1]); if(j<m&&a[i][j+1]!=-1) add(id[i][j],id[i][j+1],a[i][j+1]); if(i>1&&a[i-1][j]!=-1) add(id[i][j],id[i-1][j],a[i-1][j]); if(i<n&&a[i+1][j]!=-1) add(id[i][j],id[i+1][j],a[i+1][j]); } } for(int i=1;i<=K;i++) { dij(id[x[i]][y[i]]); for(int j=1;j<=K;j++) { ma[i][j]=dis[id[x[j]][y[j]]]; } } int N=(1<<K); for(int i=0;i<N;i++) for(int j=0;j<K;j++) dp[i][j]=inff; for(int i=0;i<K;i++) dp[(1<<i)][i]=ma[0][i+1]; int ans=inff; for(int i=1;i<N;i++) { int flog=1; for(int j=0;j<K;j++) { if(!(i&(1<<j))) { flog=0; continue; } for(int k=0;k<K;k++) { if(j==k||!(i&(1<<k))) continue; dp[i][j]=min(dp[i][j],dp[i^(1<<j)][k]+ma[k+1][j+1]); } } if(flog) { for(int j=0;j<K;j++) ans=min(ans,dp[i][j]+ma[j+1][0]); } } if(ans==inff) puts("0"); else printf("%d\n",ans); } return 0; }