问题 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就行了,因为
P≤12
所以说刚刚好。
注意,可能有重边!!!
#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
*/