题目传送门
题目大意
已知m条无向边和权值,从1点出发送外卖到k个点后回到1点,求最短路
思路
将所有的出发点全部跑一遍最短路(dijkstra),然后二维数组存储路径后dfs或者状压DP求最短路即可
AC Code
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define int long long
// 分别对应边和点
const int M=15;
const int N=2e5 +9;
int n, m, k, S, T, flag[M];
int dis[N], sum, ans, f[M][M];
bool vis[N];
int head[N], cnt;
struct Node {
int u;
int dis;
bool operator < (const Node &x) const {
return dis > x.dis;
}
Node(int u, int dis) : u(u), dis(dis) {}
};
struct Edge {
int v, next;
int w;
} e[2 * N];
void add(int u, int v, int w) {
e[++cnt].v = v;
e[cnt].w = w;
e[cnt].next = head[u];
head[u] = cnt;
}
void dijkstra(int s) {
priority_queue <Node> q;
for (int i = 1; i <= n; ++i) {
dis[i] = INF;
vis[i] = false;
}
dis[s] = 0;
q.push(Node(s, 0));
while (!q.empty()) {
Node temp = q.top();
q.pop();
if (vis[temp.u]) {
continue;
}
vis[temp.u] = true;
for (int i = head[temp.u]; i; i = e[i].next) {
int v = e[i].v;
int len = e[i].w;
if (!vis[v] && dis[v] > dis[temp.u] + len) {
dis[v] = dis[temp.u] + len;
q.push(Node(v, dis[v]));
}
}
}
}
// dfs求所有可行路,x记录走过的点的个数,fa记录当前位置
void dfs(int x,int fa){
// dfs终止情况,即为走到倒数第二步,因最后一步位置确定,故直接取最小值即可
if(x==k){
ans=min(ans,sum+f[fa][k+1]);
return;
}
// 求得当前fa可到其他点的所有情况
for(int i=1;i<=k;i++){
if(!vis[i]){
vis[i]=1;
sum+=f[fa][i];
dfs(x+1,i);
vis[i]=0;
sum-=f[fa][i];
}
}
}
signed main(){
int u,v,w;
cin>>n>>m>>k;
S=T=1; // 起点和终点均为1
flag[0]=S;flag[k+1]=T; // 0记录起点,k+1记录终点
for(int i=1;i<=k;i++){
cin>>flag[i];
}
for(int i=1;i<=m;i++){
cin>>u>>v>>w;
add(u,v,w);
add(v,u,w);
}
// 对每个点都用dijkstra求得到其他点的最短路
for(int i=0; i<=k+1;i++){
dijkstra(flag[i]);
for(int j=0;j<=k+1;j++) f[j][i]=f[i][j]=dis[flag[j]]; // 将i到达需要达到的点的距离全部记录进f
}
memset(vis,0,sizeof(vis));
ans=INF, sum=0;
// 将0记为根结点开始dfs求记录数据的最短路和
dfs(0,0);
if(ans==INF) cout<<-1<<endl;
else cout<<ans<<endl;
return 0;
}