JZOJsenior3470.【NOIP2013模拟联考8】最短路(path)

problem

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

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。


analysis

看到 0k10 k 非常的小,那么正解就是暴力不要问问题

预处理的话,我们考虑先把起点s和每一个特殊点 k+1 spfa
然后暴力枚举 O(n!) 的顺序,顺序走一次,记录最小值,输出
虽说很简单但还是很考验码力(俗话码农)


code

代码有点丑蛤

#include
#include
#define MAXN 50001
#define MAXM 100001
#define MAX 10*MAXN

using namespace std;

int dist[11][MAXN],last[MAXM],next[MAXM],tov[MAXM],len[MAXM];
int queue[MAX],dis[MAXN],state[11],num[11];
bool bz[MAXN],bo[11],boolean,judge;
int n,m,k,s,t,tot;
long long ans;

void insert(int x,int y,int z)
{
    next[++tot]=last[x];
    last[x]=tot;
    tov[tot]=y;
    len[tot]=z;
}

void solve()
{   
    if (dis[num[state[1]]]>=1061109567 || dist[state[k]][t]>=1061109567)
    {
        boolean=0;
        return;
    }
    long long temp=(long long)dis[num[state[1]]]+dist[state[k]][t];
    for (int i=1;iif (dist[state[i]][num[state[i+1]]]>=1061109567)
        {
            boolean=0;
            return;
        }
        temp+=(long long)dist[state[i]][num[state[i+1]]];
    }
    if (temp10000000000)
    {   
        boolean=1;
        ans=temp;
    }
}

void dfs(int x)
{
    if (x>k)
    {
        boolean=1;
        solve();
        judge|=boolean;
        return;
    }
    for (int i=1;i<=k;i++)
    if (bz[i])
    {
        state[x]=i;
        bz[i]=0;
        dfs(x+1);
        bz[i]=1;
    }
}

void spfa()
{
    memset(dis,63,sizeof(dis));
    memset(bz,1,sizeof(bz));
    int head=0,tail=1;
    bz[s]=0;
    queue[1]=s;
    dis[s]=0;
    while (head!=tail)
    {
        head=(head+1==MAX?0:head+1);
        int now=queue[head];
        for (int i=last[now];i;i=next[i])
        {
            int j=tov[i];
            if (dis[now]+len[i]if (bz[j])
                {
                    tail=(tail+1==MAX?0:tail+1);
                    queue[tail]=j;
                    bz[j]=0;
                }
            }
        }
        bz[now]=1;
    }
}

int main()
{
    //freopen("readin.txt","r",stdin);
    scanf("%d%d%d%d%d",&n,&m,&k,&s,&t);
    for (int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        insert(x,y,z);
    }
    for (int i=1;i<=k;i++)
    {
        scanf("%d",&num[i]);
    }
    spfa();
    if (k==0)
    {
        if (dis[t]<1000000000)printf("%d\n",dis[t]);
        else printf("-1\n");
        return 0;
    }
    for (int t=1;t<=k;t++)
    {
        memset(dist[t],63,sizeof(dist[t]));
        memset(queue,0,sizeof(queue));
        memset(bz,1,sizeof(bz));
        int head=0,tail=1;
        queue[1]=num[t];
        dist[t][num[t]]=0;
        bz[num[t]]=0;
        while (head!=tail)
        {
            head=(head+1==MAX?0:head+1);
            int now=queue[head];
            for (int i=last[now];i;i=next[i])
            {
                int j=tov[i];
                if (dist[t][now]+len[i]if (bz[j])
                    {
                        tail=(tail+1==MAX?0:tail+1);
                        queue[tail]=j;
                        bz[j]=0;
                    }
                }
            }
            bz[now]=1;
        }
    }
    judge=0;
    ans=1000000000000007;
    dfs(1);
    if (judge)printf("%lld\n",ans);
    else printf("-1");
    return 0;
}

你可能感兴趣的:(模拟赛,最短路,图论,暴力,dfs)