题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4640
思路:首先把每个点是否经过状态压缩为0,1,经过为1,不经过为0,求出1~((1<<n)-1)间所有状态的一个人走时的最小时间,怎么求呢,用dp思想,dis[i][j]表示走完i状态,并且最后停在j点上所用的最小时间,把所有的点从1~n变为0~n-1,起点由原来的1变成了0,初始设置dis[1<<0][0]=0,表示走完0这个点,并且最后停在0这个位置上所化的最小时间,对于和0相连的点,比如说2和0相连,则dis[(1<<0)|(1<<2)][2]=dis[1<<0][0]+weight
最后用0,1背包求出最小多个人的
AC代码
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline bool scan_d (T &ret) {
char c;
int sgn;
if (c = getchar(), c == EOF) return 0; //EOF
while (c != '-' && (c < '0' || c > '9') ) {
if((c = getchar()) == EOF) return 0;
}
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
template<typename T>
void print(T x) {
static char s[33], *s1; s1 = s;
if (!x) *s1++ = '0';
if (x < 0) putchar('-'), x = -x;
while(x) *s1++ = (x % 10 + '0'), x /= 10;
while(s1-- != s) putchar(*s1);
}
template<typename T>
void println(T x) {
print(x); putchar('\n');
}
#define N 18
#define inf 0x3f3f3f3f
vector<pair<int,int>>maps[N];
long long dis[1<<N][N];
long long dp[4][1<<N];
int vist[1<<N][N];
int n,m;
int ans;
struct node
{
int sta;
int root;
node(int b,int c):sta(b),root(c){}
};
void SPFA()
{
for(int i=1;i<(1<<n);++i)
{
for(int j=0;j<=n;++j)
dis[i][j]=inf;
}
for(int i=1;i<4;++i)
{
for(int j=0;j<(1<<n);++j)
dp[i][j]=inf;
}
dis[1][0]=0;
memset(vist,0,sizeof(vist));
node n1(1,0);
node n2(0,0);
int weight;
vist[1][0]=1;
queue<node>q;
q.push(n1);
while(!q.empty())
{
n1=q.front();
q.pop();
vist[n1.sta][n1.root]=0;
for(int i=0;i<maps[n1.root].size();++i)
{
n2.root=maps[n1.root][i].first;
weight=maps[n1.root][i].second;
n2.sta=n1.sta|(1<<n2.root);
if(dis[n2.sta][n2.root]>dis[n1.sta][n1.root]+weight)
{
dis[n2.sta][n2.root]=dis[n1.sta][n1.root]+weight;
if(vist[n2.sta][n2.root]==0)
{
vist[n2.sta][n2.root]=1;
q.push(n2);
}
}
}
}
}
int main()
{
int t;
int u,v,w;
int k;
scan_d<int>(t);
for(int ca=1;ca<=t;++ca)
{
scan_d<int>(n);
scan_d<int>(m);
for(int i=0;i<=n;++i)
maps[i].clear();
for(int i=1;i<=m;++i)
{
scan_d(u);
scan_d(v);
scan_d(w);
u--;
v--;
maps[u].push_back(make_pair(v,w));
maps[v].push_back(make_pair(u,w));
}
ans=0;
scan_d<int>(k);
for(int i=1;i<=k;++i)
{
int x;
scan_d<int>(x);
x--;
ans|=1<<x;
}
SPFA();
for(int i=1;i<(1<<n);++i)
{
for(int j=0;(1<<j)<=i;++j)
{
dp[1][i]=min(dp[1][i],dis[i][j]);
}
}
for(int i=2;i<=3;++i)
{
for(int j=1;j<(1<<n);++j)
{
if((j&1)==0) continue;
for(int s1=j;s1>0;s1=((s1-1)&j))
{
int temp=s1|1;
int s2=temp^j;
s2|=1;
dp[i][j]=min(dp[i][j],max(dp[i-1][temp],dp[1][s2]));
}
}
}
long long result=inf;
for(int i=1;i<(1<<n);++i)
{
if((i&ans)==ans)
result=min(dp[3][i],result);
}
if(result==inf)
printf("Case %d: -1\n",ca);
else
printf("Case %d: %d\n",ca,result);
}
return 0;
}