地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=6166
题目:
Senior Pan
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 245 Accepted Submission(s): 71
Problem Description
Senior Pan fails in his discrete math exam again. So he asks Master ZKC to give him graph theory problems everyday.
The task is simple : ZKC will give Pan a directed graph every time, and selects some nodes from that graph, you can calculate the minimum distance of every pair of nodes chosen in these nodes and now ZKC only cares about the minimum among them. That is still too hard for poor Pan, so he asks you for help.
Input
The first line contains one integer T, represents the number of Test Cases.1≤T≤5.Then T Test Cases, for each Test Cases, the first line contains two integers n,m representing the number of nodes and the number of edges.1≤n,m≤100000
Then m lines follow. Each line contains three integers xi,yi representing an edge, and vi representing its length.1≤xi,yi≤n,1≤vi≤100000
Then one line contains one integer K, the number of nodes that Master Dong selects out.1≤K≤n
The following line contains K unique integers ai, the nodes that Master Dong selects out.1≤ai≤n,ai!=aj
Output
For every Test Case, output one integer: the answer
Sample Input
1
5 6
1 2 1
2 3 3
3 1 3
2 5 1
2 4 2
4 3 1
3
1 3 5
Sample Output
Case #1: 2
Source
2017 Multi-University Training Contest - Team 9
思路:
官方题解看的有点迷,看了半天才懂。
就是把k个关键点分为两个点集st,se,两个点集间的最短距离可以通过两次dijkstra或者spfa求出来。
所以现在的关键问题是怎么划分点集,使得任意点对都会被划分到不同点集中。
一次划分显然是不可能的,所以可进行有限次划分满足上面的要求。
考虑到任意不同数对x,y。x,y在二进制下必有一位不相同。
所以可以通过二进制位进行20次划分,这样就可以覆盖所有情况。
同时还有一种随机做法,就是进行t次random_shuffle用来划分点集。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define MP make_pair 6 #define PB push_back 7 typedef long long LL; 8 typedef pair<int,int> PII; 9 const double eps=1e-8; 10 const double pi=acos(-1.0); 11 const int K=1e5+7; 12 const int mod=1e9+7; 13 14 vector<PII >mp[K]; 15 vector<int>key,st,se; 16 LL dis[K]; 17 int n,m,k; 18 19 LL spfa(vector<int> &s,vector<int> &e) 20 { 21 queue<int>q; 22 fill(dis+1,dis+n+1,1e12); 23 for(auto &x:s) 24 q.push(x),dis[x]=0; 25 while(q.size()) 26 { 27 int u=q.front();q.pop(); 28 for(auto &v:mp[u]) 29 if(dis[v.first]>dis[u]+v.second) 30 { 31 dis[v.first]=dis[u]+v.second; 32 q.push(v.first); 33 } 34 } 35 LL ret=1e15; 36 for(auto &x:e) 37 ret=min(ret,dis[x]); 38 return ret; 39 } 40 int main(void) 41 { 42 //freopen("in.acm","r",stdin); 43 int t,cs=1;cin>>t; 44 while(t--) 45 { 46 memset(mp,0,sizeof mp); 47 key.clear(); 48 LL ans=1e15; 49 scanf("%d%d",&n,&m); 50 for(int i=1,x,y,z;i<=m;i++) 51 scanf("%d%d%d",&x,&y,&z),mp[x].PB(MP(y,z)); 52 scanf("%d",&k); 53 for(int i=1,x;i<=k;i++) 54 scanf("%d",&x),key.PB(x); 55 for(int i=0;i<=20;i++) 56 { 57 st.clear(),se.clear(); 58 for(auto &x:key) 59 if(x&(1<<i)) 60 st.push_back(x); 61 else 62 se.push_back(x); 63 ans=min(ans,min(spfa(st,se),spfa(se,st))); 64 } 65 printf("Case #%d: %lld\n",cs++,ans); 66 } 67 return 0; 68 }