新年好

https://loj.ac/problem/10078

题目描述

  佳佳在节点1,需要访问5个亲戚(顺序任意),求访问时的最短路(不用回来)。

思路

  考虑到这道题n、m都不算大,亲戚个数也不多,我们可以暴力队节点1和每一个目标节点做一次Dijkstra,求出这几个点和其他点的最短路后,暴力枚举每个亲戚的排列顺序,对所有方案取最小值即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=50005,M=1e5+10,INF=1e8;
int head[N],nxt[M<<1],to[M<<1],w[M<<1],tot;
int dis[N][6],ans=INF,n,m;
int goal[6];
bool vis[N],used[10];
void add_edge(int x,int y,int v)
{
    nxt[++tot]=head[x];
    head[x]=tot;
    to[tot]=y;
    w[tot]=v;
}
void Dijkstra(int s,int cnt)
{
    priority_queue<pair<int,int> >q;
    for(int i=1;i<=n;i++)dis[i][cnt]=INF;
    memset(vis,0,sizeof(vis));
    dis[s][cnt]=0;q.push(make_pair(0,s));
    while(!q.empty())
    {
        int u=q.top().second;q.pop();
        if(vis[u])continue ;
        vis[u]=1;
        for(int i=head[u];i;i=nxt[i])
        {
            int v=to[i];
            if(dis[v][cnt]>dis[u][cnt]+w[i])
            {
                dis[v][cnt]=dis[u][cnt]+w[i];
                q.push(make_pair(-dis[v][cnt],v));
            }
        }
    }
}
void dfs(int k,int st,int sum)
{
//    cout<<k<<' '<<st<<' '<<sum<<endl;
    if(k==5)
    {
        ans=min(ans,sum);
        return ;
    }
    for(int i=1;i<6;i++)
        if(!used[i])
        {
            used[i]=1;
            dfs(k+1,i,sum+dis[goal[i]][st]);
            used[i]=0;
        }
}
int main() 
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=5;i++)
        scanf("%d",&goal[i]);
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        add_edge(x,y,z);
        add_edge(y,x,z);
    }
    Dijkstra(1,0);
    for(int i=1;i<=5;i++)
        Dijkstra(goal[i],i);
    dfs(0,0,0);    
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/fangbozhen/p/11683225.html