Senior Pan
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 166 Accepted Submission(s): 39
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.
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
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
Recommend
liuyiding
题目大意:
有一张有向图,给你一个点集,问点集之间的任意两点的距离的最小值。
解题思路:
由于点集可以非常大,直接枚举显然会超时。可以发现,如果把点集划分成两个子集,我们可以使用一次dijkstra求出两个子集间的最短路。如果我们根据点的编号的二进制的每一位,根据这一位为0还是1可以划分子集,就可以把任意两点至少一次划分到两个子集中。所以最终答案一定就是每次dijkstra求得的最短距离的最小值。
AC代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
#include <string>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define LL long long
#define fi first
#define se second
#define mem(a,b) memset((a),(b),sizeof(a))
const int MAXN=100000+3;
struct Edge//边
{
int to, cost;
Edge(int t, int c):to(t), cost(c){}
};
struct Node//候选构成最短路的点
{
int u;
LL c;
Node(int u, LL c):u(u), c(c){}
bool operator < (const Node &other)const
{
return c>other.c;
}
};
int N, M, K;
vector<Edge> G[MAXN];//图的邻接表表示
vector<int> save;//询问的点集
LL ans;
bool vis[MAXN];
LL dist[MAXN];
void init()
{
for(int i=0;i<=N;++i)
G[i].clear();
save.clear();
ans=INF;
}
void dij(int p, int x)//根据编号第p位划分,第p位为x的作起点
{
for(int i=1;i<=N;++i)//当前位为x,则作为起点
{
vis[i]=false;
dist[i]=INF;
}
priority_queue<Node> que;
for(int i=0;i<save.size();++i)
if(((save[i]>>p)&1)==x)
{
dist[save[i]]=0;
que.push(Node(save[i], 0));
}
while(!que.empty())
{
Node tmp=que.top(); que.pop();
int u=tmp.u;
if(vis[u])
continue;
vis[u]=true;
for(int i=0;i<G[u].size();++i)
{
int v=G[u][i].to;
if(!vis[v] && dist[v]>dist[u]+G[u][i].cost)
{
dist[v]=dist[u]+G[u][i].cost;
que.push(Node(v, dist[v]));
}
}
}
for(int i=0;i<save.size();++i)//当前位不为x,则作为终点
if(((save[i]>>p)&1)!=x)
ans=min(ans, dist[save[i]]);
}
int main()
{
int T_T;
scanf("%d", &T_T);
for(int cas=1;cas<=T_T;++cas)
{
scanf("%d%d", &N, &M);
init();
for(int i=0;i<M;++i)
{
int u, v, c;
scanf("%d%d%d", &u, &v, &c);
G[u].push_back(Edge(v, c));
}
scanf("%d", &K);
for(int i=0;i<K;++i)
{
int tmp;
scanf("%d", &tmp);
save.push_back(tmp);
}
for(int p=0;p<=16;++p)//根据第p位划分,编号最大为1e5,二进制有16位
{
dij(p, 0);//由于是有向图,两个集合分别作起点终点的情况
dij(p, 1);//似乎数据比较水,不枚举这种情况也能过
}
printf("Case #%d: %lld\n", cas, ans);
}
return 0;
}