首先这个题化成两个集合还是很容易的想到的,但是不知道怎么用二进制表示,感觉这个题的脑洞还是很大的。
为什么可以用二进制表示化成集合可以包含所有的点对,因为要是两个数不同的话肯定会有一个二进制的位数不同
所以就包含了所有的点对。
#include<stdio.h> #include<string.h> #include<algorithm> #include<queue> using namespace std; const int N=5e5; struct node { int u,v; long long w; }s[N]; int node[N],nxt[N],head[N]; int n,m,tot,begins,vis[N]; long long d[N],data[N]; void add(int x,int y,long long z) { node[++tot]=y;nxt[tot]=head[x];head[x]=tot;data[tot]=z; } void inist() { //memset(vis,0,sizeof(vis)); tot=0; memset(node,0,sizeof(node)); memset(head,0,sizeof(head)); memset(data,0,sizeof(data)); } void Dij() { for(int i=1;i<=n+2;i++) d[i]=10000000000000LL; d[begins]=0; priority_queue<pair<long long,long long> > heap; heap.push(make_pair(-d[begins],begins)); while (1){ for (;!heap.empty() && -d[heap.top().second]!=heap.top().first;heap.pop()); if (heap.empty()) break; int now=heap.top().second; heap.pop(); for (int i=head[now];i;i=nxt[i]){ int j=node[i]; if (d[j]>d[now]+data[i]){ d[j]=d[now]+data[i]; heap.push(make_pair(-d[j],j)); } } } } int main() { int t; scanf("%d",&t); int id=0; while(t--) { memset(vis,0,sizeof(vis)); id++; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%d%lld",&s[i].u,&s[i].v,&s[i].w); } int k; scanf("%d",&k); for(int i=1;i<=k;i++) { int x; scanf("%d",&x); vis[x]=1; } int num=1; long long ans=100000000000000LL; while(num!=20) { inist(); for(int i=1;i<=m;i++) { int u=s[i].u,v=s[i].v; if(vis[u]) { if(u&(1<<(num-1))) { u=n+1; } else u=n+2; } if(vis[v]) { if(v&(1<<(num-1))) { v=n+1; } else v=n+2; } add(u,v,s[i].w); } //begins=n+1; // Dij(); //ans=min(ans,d[n+2]); begins=n+2; Dij(); ans=min(ans,d[n+1]); num++; } printf("Case #%d: ",id); printf("%lld\n",ans); } }