因为n的范围限制,所以用壮压就可以了
大佬说0-n!可以用暴力搜索
10-25可以用壮压。
太大用壮压也不行了
给定一个矩阵,和一些有财富点的点,问你从任意点进去,遍历所有财富点,最后出去的最小话费。
(花费为路径经过的地方的值的总和)
仰慕我校大佬。
因为对任意财富点的访问时n!的
所以是tsp,要想转换成tsp,首先要得到最短的路径
各个财富点之间的,和财富店和边界之间的。
在进行spfa的同时,顺便吧最近的距离财富店的距离也给求了
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
const int maxn=205;
int n,m;
int fx[4][2]= {1,0,0,1,-1,0,0,-1};
int dis[maxn][maxn],a[maxn][maxn],dis_border[25],length[20][20];
bool vis[maxn][maxn];
int dp[1<<15][15];
int ff[maxn];
int tt[maxn];
void spfa(int s)
{ /*for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
dis[i][j]=0x3f3f3f3f;*/
memset(dis,0x3f,sizeof(dis));
memset(vis,false,sizeof(vis));
queue<pair<int,int> >q;
q.push(make_pair(ff[s],tt[s]));
vis[ff[s]][tt[s]]=true;
dis[ff[s]][tt[s]]=0;
while(!q.empty())
{ int x=q.front().first;
int y=q.front().second;
q.pop();
vis[x][y]=false;
if(x==0||x==n-1||y==0||y==m-1)
dis_border[s]=min(dis_border[s],dis[x][y]);
for(int i=0;i<4;i++)
{ int xx=x+fx[i][0];
int yy=y+fx[i][1];
if(xx<0||xx>n-1||yy<0||yy>m-1||a[xx][yy]==-1)continue;
if(dis[xx][yy]>dis[x][y]+a[xx][yy])
{ dis[xx][yy]=dis[x][y]+a[xx][yy];
if(!vis[xx][yy])
{ vis[xx][yy]=true;
q.push(make_pair(xx,yy));
}
}
}
}
}
int main()
{ int t;
int k;
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",&a[i][j]);
scanf("%d",&k);
for(int i=0;i<k;i++)
{ scanf("%d%d",&ff[i],&tt[i]);
}
for(int i=0;i<k;i++)
{
dis_border[i]=0x3f3f3f3f;
for(int j=0;j<k;j++)
{
if(i==j)
length[i][j]=0;
else
length[i][j]=0x3f3f3f3f;
}
}
for(int i=0;i<(1<<k);i++)
{
for(int j=0;j<k;j++)
{
dp[i][j]=0x3f3f3f3f;
}
}
for(int i=0;i<k;i++)
{ spfa(i);
for(int j=0;j<k;j++)
{ if(i==j) continue;
length[i][j]=min(length[i][j],dis[ff[j]][tt[j]]);
}
dp[1<<i][i]=dis_border[i]+a[ff[i]][tt[i]];
//length[i][j]+=
}
for(int i=0;i<(1<<k);i++)
{
for(int j=0;j<k;j++)
{ if((i&1<<j)==0)continue;
if(dp[i][j]==0x3f3f3f3f) continue;
for(int s=0;s<k;s++)
{ if((i&(1<<s))==1) continue;
dp[i|(1<<s)][s]=min(dp[i|(1<<s)][s],dp[i][j]+length[j][s]);
}
}
}
int ans=0x3f3f3f3f;
for(int i=0;i<k;i++)
{
ans=min(ans,dp[(1<<k)-1][i]+dis_border[i]);
}
/*要加两次disborder的原因是一次是要进的,另一次是出的
*/
cout<<ans<<endl;
}
}