[Solution] JZOJ3470 最短路

[Solution] JZOJ3470 最短路

题面

Description

给定一个n个点m条边的有向图,有k个标记点,要求从规定的起点按任意顺序经过所有标记点到达规定的终点,问最短的距离是多少。

Input

第一行5个整数n、m、k、s、t,表示点个数、边条数、标记点个数、起点编号、终点编号。

接下来m行每行3个整数x、y、z,表示有一条从x到y的长为z的有向边。

接下来k行每行一个整数表示标记点编号。

Output

输出一个整数,表示最短距离,若没有方案可行输出-1。

Sample Input

3 3 2 1 1

1 2 1

2 3 1

3 1 1

2

3

扫描二维码关注公众号,回复: 2700407 查看本文章

Sample Output

3

【样例解释】

路径为1->2->3->1。

Data Constraint

20%的数据n<=10。

50%的数据n<=1000。

另有20%的数据k=0。

100%的数据n<=50000,m<=100000,0<=k<=10,1<=z<=5000。

-------------


# 分割线

-------------

解题思路

这个题很显然是一个最短路的问题,主要分为一下步骤

Step1:预处理出起点终点和k个关键点之间的最短路

Step2:因为看到了0<=k<=10所以可以暴力搜路过点顺序的全排列

Step3:不要忘记剪枝

复杂度O(knlogn+k!)

具体见Code


Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<vector>
#define maxn 50006
#define inf 0x3f3f3f3f3f3f3f3f
#define ll long long
using namespace std;
ll dis[maxn];
ll book[maxn];
ll f[15][15];
ll n,m,k,p,q;
struct Edge{
    ll t,w,nxt;
}edge[maxn*2];
ll head[maxn],tot=0;
ll kk[20];
ll ans=inf,num=0;
priority_queue< pair<ll,ll> > hep;
ll gmin(ll a,ll b){return a<b?a:b;}
void add(ll st,ll to,ll we){edge[tot].t=to;edge[tot].w=we;edge[tot].nxt=head[st];head[st]=tot;tot++;}
void init(){
    memset(head,-1,sizeof(head)); 
    scanf("%lld %lld %lld %lld %lld",&n,&m,&k,&p,&q);
    for(ll i=1;i<=m;i++){
        ll a,b,c;scanf("%lld %lld %lld",&a,&b,&c);
        add(a,b,c);
        if(b==q)
            add(a,n+1,c);
    }
    for(ll i=1;i<=k;i++)
        scanf("%lld",kk+i);
    kk[0]=p;kk[k+1]=n+1;
    return;
}
void dij(ll s){
    ll ss=s;
    s=kk[s];
    memset(dis,0x3f,sizeof(dis));
    memset(book,0,sizeof(book));
    while(!hep.empty()) hep.pop();
    dis[s]=0;
    hep.push(make_pair(0-dis[s],s));
    while(!hep.empty()){
        ll ns=hep.top().second;
        hep.pop();
        if(book[ns]) continue;
        book[ns]=1;
        for(ll i=head[ns];i!=-1;i=edge[i].nxt){
            ll t=edge[i].t;
            if(dis[t]>dis[ns]+edge[i].w){
                dis[t]=dis[ns]+edge[i].w;
                hep.push(make_pair(0-dis[t],t));
            }
        }
    }
    for(ll i=0;i<=k+1;i++)
        f[ss][i]=dis[kk[i]];
    return;
}
void dfs(ll dep,ll st){
    if(num>=ans) return;
    if(dep==k){
        if(f[st][k+1]!=inf){
            num+=f[st][k+1];
            ans=gmin(ans,num);
            num-=f[st][k+1];
        }return;
    }
    for(ll i=1;i<=k;i++) if(!book[i])
        if(f[st][i]!=inf){
            book[i]=1;
            num+=f[st][i];
            dfs(dep+1,i);
            num-=f[st][i];
            book[i]=0;
        }
}
void solve(){
    for(ll i=0;i<=k;i++)
        dij(i);
    if(k==0)
        if(f[0][1]!=inf){
            printf("%lld\n",f[0][1]);return;
        }
        else{
            printf("-1\n");return;
        }
    memset(book,0,sizeof(book));
    for(ll i=1;i<=k;i++)if(f[0][i]!=inf){
        memset(book,0,sizeof(book));
        num+=f[0][i];
        book[i]=1;
        dfs(1,i);
        book[i]=0;
        num-=f[0][i];
    }
    if(ans==inf)
        printf("-1\n");
    else
        printf("%lld\n",ans);
    return;
}
int main(){
    init();
    solve();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/theOldChun/p/9460738.html
今日推荐