题意:一开始就在旅游的几个点选一个作为起点,然后这个点就算游过了,游完别的景点在最后一个景点停下即可。
用dp[i][j],i表示状态(哪些点游过,哪些点没有),j表示最后停留在哪个点。
具体看代码详细注释:
#include <bits/stdc++.h>
using namespace std;
int n,m,r;
const int N=205;
const int INF=0x3f3f3f3f;
int rs[18];//表示必须要旅游的点
int mp[N][N];
int dp[34000][20];
void floyed()
{
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++) mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&r);
for(int i=1;i<=r;i++) scanf("%d",&rs[i]);
memset(mp,INF,sizeof(mp));
memset(dp,INF,sizeof(dp));
while(m--)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
mp[u][v]=mp[v][u]=w;
}
floyed();
for(int i=1;i<=r;i++)
{
dp[1<<(i-1)][i]=0; //最开始走的那一个点,是没有花费的
}
int len=(1<<r)-1;
for(int i=1;i<len;i++)//枚举状态
{
for(int j=1;j<=r;j++)//枚举起始位置
{
int jj=1<<(j-1);
if(!(i&jj)) continue;//起始位置肯定是走过的
for(int k=1;k<=r;k++)//枚举终止位置
{
int kk=1<<(k-1);
if(i&kk) continue;//终止位置一定是一个新位置
dp[i|kk][k]=min(dp[i|kk][k],dp[i][j]+mp[rs[j]][rs[k]]);
}
}
}
int ans=INF;
for(int i=1;i<=r;i++)
{
ans=min(ans,dp[len][i]);
}
printf("%d\n",ans);
}


京公网安备 11010502036488号