最近突然想起很久以前同学问的一道数模题,是道NPC问题,当时不会搞,现在发现用状压可以搞出来,所以就把这个坑填上了
设状态(S,u)表示已访问过的景点集合为S且当前在第u个景点,用求最短路的方式进行转移即可。
虽然题目说每个景点可以经过多次,但最优路线还是每个景点都只经过了一次,囧…
ps:原代码的Dijkstra算法有误,现已更正(spfa用惯了,Dijkstra都不会写了,唉)
更新日期2019.1.5
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int N=10;
int dis[N][N]= {
{0,300,360,210,590,475,500,690},
{300,0,380,270,230,285,200,390},
{360,380,0,510,230,765,580,770},
{210,270,510,0,470,265,450,640},
{590,230,230,470,0,515,260,450},
{475,285,765,265,515,0,460,650},
{500,200,580,450,260,460,0,190},
{690,390,760,640,450,650,190,0},
};
int d[1<<N][N],vis[1<<N][N];
struct node {
int S,u;
node(int S=0,int u=0):S(S),u(u) {}
bool operator<(const node& b)const {
return d[S][u]>d[b.S][b.u];
}
};
node pre[1<<N][N];
void printans(int S,int u) {
if(u!=0)printans(pre[S][u].S,pre[S][u].u);
printf("%d ",u);
}
int Dij() {
memset(d,INF,sizeof d);
memset(vis,0,sizeof vis);
priority_queue<node> q;
q.push(node(1<<0,0));
d[1<<0][0]=0;
while(!q.empty()) {
int S=q.top().S,u=q.top().u;
q.pop();
if(vis[S][u]||u==7)continue;
vis[S][u]=1;
for(int v=1; v<8; ++v) {
int S2=S|(1<<v);
if(d[S2][v]<=d[S][u]+dis[u][v])continue;
d[S2][v]=d[S][u]+dis[u][v];
pre[S2][v]=node(S,u);
q.push(node(S2,v));
}
}
return d[(1<<8)-1][7];
}
int main() {
printf("%d\n",Dij());
printans((1<<8)-1,7);
return 0;
}
求得最短路为1820
路线为 0 3 5 1 2 4 6 7