【Floyd+旅行商】【CQBZOJ 2572】Ali 的宝藏

问题 F(2572): Ali 的宝藏
时间限制: 1 Sec 内存限制: 128 MB

题目描述
阿狸是很财迷的!他喜欢收集宝藏。
阿狸秘密的了解到花园里面藏有 P 个宝藏。经过严密调查, 他知道花园分成了 N块
区域,由M 条无向路径连接。
阿狸要从1 区域出发,捡完所有的宝藏后从 N 区域离开。阿狸被发财的白日梦冲昏了头脑,没有办法冷静下来想想挖宝的对策,于是鸡冻的他找你帮忙:最短走多远就能捡完宝藏并离开?

输入
第1行两个整数M, N。
第2行到第M + 1 行, 每行三个整数x 、y 、w,表示x、y号区域(1 ≤ x、y ≤ N)
间有一条道路,该道路长度为w。
第M + 2行一个整数 P。
第M + 3 行有用空格隔开的 P 个整数,第 i 个数Pi代表第 i 个珍品藏在第Pi个区域。

输出
第 1 行为一个整数,为阿狸拿到所有宝藏并离开的所需走过的最短道路长度。 如
无法全部捡到或者无法离开,输出-1 。

样例输入
2 3
1 2 3
2 3 4
1
2

样例输出
7

【数据范围】
1 ≤ N ≤ 200,1 ≤ M ≤ 10000,0 ≤ P ≤ 12,道路长度不超过 1000000000

这道题就是一道究极大水题,只要Floyd求出两两点间的最短路后状压DP就行了,因为 P12 所以说刚刚好。
注意,可能有重边!!!

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;

#define MAXN 200
#define MAXP 12
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3fll
typedef long long int LL;

LL getint()
{
    LL rn=0;
    char c=getchar();

    while(c<'0'||'9'<c)
        c=getchar();

    while('0'<=c&&c<='9')
    {
        rn=rn*10+c-'0';
        c=getchar();
    }

    return rn;
}

LL dist[MAXN+10][MAXN+10];
int pos[MAXP+5];
int N,M,P;

LL dp[MAXP+5][(1<<MAXP)+100];

int main()
{
    M=getint(),N=getint();
    int i,j,k;
    LL a,b,c;

    memset(dist,0x3f,sizeof(dist));
    for(i=1;i<=N;++i)dist[i][i]=0;

    for(i=1;i<=M;++i)
    {
        a=getint(),b=getint(),c=getint();
        dist[a][b]=dist[b][a]=min(dist[a][b],c);
    }

    P=getint();
    for(i=1;i<=P;++i)
        pos[i]=getint();

    for(k=1;k<=N;++k)
        for(i=1;i<=N;++i)if(i!=k)
            for(j=1;j<=N;++j)if(j!=k&&j!=i)
                dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);

    memset(dp,0x3f,sizeof(dp));
    for(i=1;i<=P;++i)
        dp[i][1<<(i-1)]=dist[1][pos[i]];

    int S=(1<<P)-1;
    for(i=1;i<=S;++i)
        for(j=1;j<=P;++j)if(i&(1<<(j-1)))
            for(k=1;k<=P;++k)if(j!=k)
                dp[k][i|(1<<(k-1))]=min(dp[k][i|(1<<(k-1))],dp[j][i]+dist[pos[j]][pos[k]]);

    LL ans=LLF;
    for(i=1;i<=P;++i)
        ans=min(ans,dp[i][S]+dist[pos[i]][N]);
    printf("%lld\n",ans<LLF?ans:-1);
}

/*
3 3
1 2 3
1 3 2
2 3 2
2
1
2
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值