新年好~
思路:
预处理,求六遍dijkstra,处理出1,a,b,c,d,e
到图中各点的单源最短路。
然后枚举所有从1
出发的方案,比如1->a->c->d->b->e
就是其中之一,将这些方案的路径和求个最小值即可(已经在预处理中解决了路径问题)。 而在这一步中,可以用dfs,也可以直接用STL中的next_permutation
来解决。
代码出现的变量等数据解释:
id[x]
表示下标为 $x$ 的点编号,我们规定id[1]=1
,在样例中,id[x]
恰好为x
。
d[x][]
表示从相应下标 $x$ 对应的点出发到其他点的单源最短路。
dijk(int st,int dist[])
st
表示源点的id
。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=5e4+5, M=1e5+5;
const int INF=0x3f3f3f3f;
int head[N],tot;
struct node{
int to,w,next;
}e[M<<1];
void add(int u,int v,int w){e[tot].to=v;e[tot].w=w;e[tot].next=head[u];head[u]=tot++;}
int n,m;
int id[7];
int d[7][N];
void dijk(int st,int dist[]){
bool vis[N]={0};
dist[st]=0;
priority_queue<PII,vector<PII>,greater<PII>> pque;
pque.push({0,st});
while(pque.size()){
auto hd=pque.top(); pque.pop();
int ver=hd.second;
if(vis[ver]) continue;
vis[ver]=true;
for(int i=head[ver];~i;i=e[i].next){
int go=e[i].to;
if(dist[go]>dist[ver]+e[i].w){
dist[go]=dist[ver]+e[i].w;
pque.push({dist[go],go});
}
}
}
}
int main(){
memset(head,-1,sizeof head);
memset(d,0x3f,sizeof d);
cin>>n>>m;
id[1]=1;
for(int i=2;i<=6;i++) cin>>id[i];
while(m--){
int u,v,w;
cin>>u>>v>>w;
add(u,v,w); add(v,u,w);
}
for(int i=1;i<=6;i++) dijk(id[i],d[i]);
int a[7];
for(int i=1;i<=6;i++) a[i]=i;
int ans=INF;
do{
int rec=0;
rec+=d[a[1]][id[a[2]]];
for(int i=2;i<=5;i++) rec+=d[a[i]][id[a[i+1]]];
ans=min(ans,rec);
}while(next_permutation(a+2,a+1+6));
cout<<ans<<endl;
return 0;
}
学习打卡
结构体前向星好评!
会不会比一般的快一些?
大部分情况会吧,可以节省内存访问的时间
void dijk(int st,int dist[]){
memset(dist,0x3f,sizeof dist);
这里的memset多此一举了,因为你在main里就全部初始化了。
y总是每次dijk才初始化一行 memset(dist,0x3f,4*N)
的确
远古时代的代码了qwq,已修
next_permutian和直接搜时间复杂度有任何不同么?
常数小一些而且代码难度小
所以 $a + 1 + 6$ 和 $a + 7$ 有什么区别。
没有区别
所以为什么要写 $a + 1 + 6$
因为区间是左闭右开的,这样可以突出右端点是 $6$
刚打卡完这题 发现思路一样
好诶( ̄︶ ̄*))
给你这篇题解点个赞