我们需要求 遍历图中的 起点 a b c d e 这6个点 的最短路径之和 我们发现每两个点之间可以看作单源最短路问题 那么思路是枚举遍历的顺序 每个顺序做5次最短路 这样的时间为 5!*mlogn 显然不是一个非常乐观的时间。
我们采取的方案是先跑最短路 用二维数组存储不同起点的最短路 然后再全排列枚举 达到 空间换时间 的效果。
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
typedef pair<int,int>PII;
int n,m;
int d[10];
int h[N],e[N],ne[N],w[N],idx;
int dist[10][N];
bool st[N];
int path[10];//记录顺序
int ans=0x3f3f3f3f;
void add(int a,int b,int c)
{
e[idx]=b;ne[idx]=h[a];w[idx]=c;h[a]=idx++;
}
void dijkstra(int start)
{
memset(st,0,sizeof st);
priority_queue<PII,vector<PII>,greater<PII>>heap;
heap.push({0,d[start]});
dist[start][d[start]]=0;
while(!heap.empty())
{
auto t=heap.top();
heap.pop();
int dis=t.first,ver=t.second;
if(st[ver])continue;
st[ver]=true;
for(int i=h[ver];i!=-1;i=ne[i])
{
int z=e[i];
if(dist[start][z]>dist[start][ver]+w[i])
{ dist[start][z]=dist[start][ver]+w[i];
heap.push({dist[start][z],z});
}
}
}
}
bool stu[10];
void dfs(int u)
{
if(u==6)
{ int res=0;
res=dist[6][d[path[1]]];
for(int i=1;i<5;i++)
{
res+=dist[path[i]][d[path[i+1]]];
}
ans=min(res,ans);
}
for(int i=1;i<=5;i++)
{
if(!stu[i])
{
path[u]=i;
stu[i]=true;
dfs(u+1);
stu[i]=false;
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=5;i++)
{
cin>>d[i];
}
memset(h,-1,sizeof h);
memset(dist,0x3f,sizeof dist);
for(int i=0;i<m;i++)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
d[6]=1;
dijkstra(6);
for(int i=1;i<=5;i++)
{
dijkstra(i);//以d[i]为起点
}
dfs(1);
cout<<ans<<endl;
}
作者:逢时
链接:https://www.acwing.com/activity/content/code/content/6784034/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
给出状压dp的代码 :
#include <bits/stdc++.h>
using namespace std;
#define db double
#define ll long long
#define Pir pair<int, int>
#define fi first
#define se second
#define pb push_back
#define m_p make_pair
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
/*==========ACMer===========*/
const int N = 5e4 + 10, M = 2e5 + 10, num = 6;
int n, m;
struct Edge
{
int v, w, ne;
} e[M];
int h[N], tot;
int d[10][10];
vector<int> vc;
int f[num][1 << num];
int vis[N], dis[N];
void add(int u, int v, int w)
{
e[++ tot] = { v, w, h[u] }; h[u] = tot;
}
void dijkstra(int s)
{
memset(vis, 0, sizeof vis);
memset(dis, inf, sizeof dis);
dis[s] = 0;
priority_queue<Pir, vector<Pir>, greater<Pir>> q;
q.push({ 0, s });
while (q.size())
{
int u = q.top().se; q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (int i = h[u]; i; i = e[i].ne) {
int v = e[i].v, w = e[i].w;
if (dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
q.push({ dis[v], v });
}
}
}
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 0; i < 5; i ++) {
int x; scanf("%d", &x);
vc.pb(x);
}
vc.pb(1);
int u, v, w;
for (int i = 0; i < m; i ++) {
scanf("%d %d %d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
for (int i = 0; i < vc.size(); i ++) {
dijkstra(vc[i]);
for (int j = 0; j < vc.size(); j ++) {
d[i][j] = d[j][i] = dis[vc[j]];
}
}
int cnt = 5;
int S = (1 << cnt) - 1;
memset(f, inf, sizeof f);
for (int i = 0; i < cnt; i ++) {
f[i][1 << i] = d[vc.size() - 1][i];
}
for (int s = 1; s <= S; s ++) {
for (int i = 0; i < cnt; i ++) {
if ((s >> i & 1) == 0)
{
for (int j = 0; j < cnt; j ++) {
if (s >> j & 1)
{
f[i][s | 1 << i] = min(f[i][s | 1 << i], f[j][s] + d[j][i]);
}
}
}
}
}
int ans = inf;
for (int i = 0; i < cnt; i ++) {
ans = min(ans, f[i][S]);
}
printf("%d\n", ans);
return 0;
}