题意:一开始就在旅游的几个点选一个作为起点,然后这个点就算游过了,游完别的景点在最后一个景点停下即可。
用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); }