解析:首先要预处理出0,V-1,shop之间的最短路径,然后用状压DP找出经过S中节点到达V-1的最短路,最后遍历一遍所有的S即可。
[code]:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<functional>
using namespace std;
typedef pair<int,int> PII;
const int INF = 0x3f3f3f3f;
int mp[505][505],d[20][20],dis[505];
int V,E,n,s[20],dp[1<<17][17];
priority_queue<PII,vector<PII>,greater<PII> > Q;
int shop,time;
void init(){
int i,j;
shop = -1;
for(i = 0;i < V;i++)
for(j = 0;j < V;j++) mp[i][j]=i==j?0:INF;
}
int dij(int s,int t){
memset(dis,63,V*sizeof(int));
dis[s] = 0;
Q.push(PII(dis[s],s));
int u,v;
while(!Q.empty()){
PII p = Q.top();Q.pop();
u = p.second;
if(dis[u]!=p.first) continue;
for(v = 0;v < V;v++){
if(mp[u][v]==INF||u==v) continue;
if(dis[v]>dis[u]+mp[u][v]){
dis[v] = dis[u]+mp[u][v];
Q.push(PII(dis[v],v));
}
}
}
return dis[t];
}
int main(){
int i,j,cas,T;
scanf("%d",&cas);
for(T = 1;T <= cas;T++){
scanf("%d%d%d",&V,&E,&n);
init();
int cnt = 0;
for(i = 0;i < n;i++){
scanf("%d",&s[i]);
if(s[i]==0||s[i]==V-1) cnt++;
}
s[n++] = 0;s[n++] = V-1;
sort(s,s+n);
n = unique(s,s+n)-s;
int u,v,w;
while(E--){
scanf("%d%d%d",&u,&v,&w);
mp[u][v] = min(mp[u][v],w);
}
for(i = 0;i < n;i++){
for(j = 0;j < n;j++){
if(i == j) continue;
d[i][j] = dij(s[i],s[j]);
}
}
int S,S_,Ed = (1<<n);
for(S = 0;S < Ed;S++) for(i = 0;i < n;i++) dp[S][i] = INF;
dp[1][0] = 0;
for(S = 2;S < Ed;S++){
for(i = 0;i < n;i++){
if(!(S>>i&1)) continue;
S_ = S^(1<<i);
for(j = 0;j < n;j++){
if(!(S_>>j&1)) continue;
dp[S][i] = min(dp[S][i],dp[S_][j]+d[j][i]);
}
}
}
for(S = 0;S < Ed;S++){
if(!(S&1)||!(S>>(n-1)&1)||dp[S][n-1]>=INF) continue;
int tmp = -2;
for(i = 0;i < n;i++)if(S>>i&1)tmp++;
if(shop < tmp){
shop = tmp;
time = dp[S][n-1];
}else if(shop == tmp) time = min(time,dp[S][n-1]);
}
printf("Case %d: ",T);
if(shop == -1) puts("Impossible");
else{
printf("%d %d\n",shop+cnt,time);
}
}
return 0;
}