题意:要你在一个图指定点钟找出两个距离最短的点
分析:枚举 位数, 使包含当前位数的为一个集合,不包含的为另一个集合,跑dijkstra
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cstring>
#include <vector>
#include <iostream>
using namespace std;
#define maxn 100400
#define INF (1<<30)
typedef long long int ll;
typedef pair<int,int> P;
int T;
int n , m;
bool vis[maxn];
vector<P>E[maxn];
int ans;
int k ;
int kx[maxn];
bool mark[maxn];
int d[maxn];
priority_queue<P,vector<P>,greater<P> >Q;
int dijkstra()
{
while( !Q.empty() )
{
int c = Q.top().first;
int u = Q.top().second;
Q.pop();
if( !mark[u] && vis[u] ){
return c;
}
if( c > d[u] )continue;
for(int i = 0 ; i < E[u].size() ; ++i)
{
int v = E[u][i].first;
int w = E[u][i].second;
if(d[v] > d[u] + w)
{
d[v] = d[u] + w;
Q.push(P(d[v],v));
}
}
}
return 1e9;
}
void init()
{
while(!Q.empty())Q.pop();
for(int i = 0 ; i <= n ; ++i)d[i] = INF;
for(int i = 1 ; i <= n ; ++i)if( mark[i] )d[i] = 0 , Q.push(P(0,i));
}
int main()
{
cin >> T;
int cas = 0;
while( T-- )
{
cin >> n >> m;
memset(vis,0,sizeof(vis));
for(int i = 0 ; i <= n ; ++i)E[i].clear();
for(int i = 0 ; i < m ; ++i)
{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
E[a].push_back(P(b,c));
}
cin >> k;
for(int i = 0; i < k ; ++i)scanf("%d",kx+i),vis[kx[i]] = 1;
printf("Case #%d: ",++cas);
ans = 1e9;
for(int i = 1 ; i < 20 ; ++i)
{
memset(mark,0,sizeof(mark));
for(int j = 0 ; j < k ; ++j){
if( kx[j] & ( 1 << i ) ){
mark[kx[j]] = 1;
}
}
init();
ans = min( ans , dijkstra() );
memset(mark,0,sizeof(mark));
for(int j = 0 ; j < k ; ++j){
if( !( kx[j] & ( 1 << i ) ) ){
mark[kx[j]] = 1;
}
}
init();
ans = min( ans , dijkstra() );
}
cout << ans << endl;
}
}