HDU 6166 Senior Pan

来源:互联网 发布:e路畅通怎么连接网络 编辑:程序博客网 时间:2024/06/06 03:18

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
题意:给你一个有向图,然后给你一个k个点的集合,让你求出集合中的最小点对的距离是多少。
思路:看了官方的题解,不得不说思路非常巧妙。它是按照当前的二进制位是否为1,而把k个点分成了两个集合,然后每次求两个集合的最短路,这样就包括了全部的点对情况。

#include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <algorithm>#include <queue>using namespace std;typedef long long LL;const int MAXN = 1e5+7;const LL inf = 1e10;int n,m,k;struct node{    int v,w;    node(int v,int w)    {        this->v = v;        this->w = w;    }};vector<node>head[MAXN];deque<int>q;LL dis[MAXN];bool vis[MAXN];int key[MAXN];vector<int>G0,G1;//存放0集合int cnt;LL sum;void spfa(){    while(!q.empty())    {        int u = q.front();        q.pop_front();        if(dis[u]*cnt > sum)        {            q.push_back(u);            continue;        }        vis[u] = 0;        cnt--,sum -= dis[u];        for(int i = 0,l = head[u].size(); i < l; ++i)        {            int v = head[u][i].v;            int w = head[u][i].w;            if(dis[u] + w < dis[v])            {                dis[v] = dis[u] + w;                if(!vis[v])                {                    vis[v] = 1;                    cnt++,sum += dis[v];                    if(q.empty() || dis[v] > dis[q.front()])q.push_back(v);                    else q.push_front(v);                }            }        }    }}int main(){    int t;    scanf("%d",&t);    int ca = 0;    while(t--)    {        scanf("%d%d",&n,&m);        for(int i = 1; i <= n; ++i)head[i].clear();        int u,v,w;        while(m--)        {            scanf("%d%d%d",&u,&v,&w);            head[u].push_back(node(v,w));        }        scanf("%d",&k);        for(int i = 0; i < k; ++i)        {            scanf("%d",&key[i]);        }        //枚举位置        LL ans = 1e10;        for(int bit = 0; bit < 17; ++bit)        {            G0.clear();            G1.clear();            for(int i = 0; i < k; ++i)            {                if(key[i] &(1<<bit))G0.push_back(key[i]);                else G1.push_back(key[i]);            }            for(int i = 1; i <= n; ++i)dis[i] = inf;            cnt = 0,sum = 0;            for(int i = 0,l = G0.size(); i < l; ++i)            {                cnt++;                q.push_back(G0[i]);                dis[G0[i]] = 0;                vis[G0[i]] = 1;            }            spfa();            for(int i = 0,l = G1.size(); i < l; ++i)ans = min(ans,dis[G1[i]]);            for(int i = 1; i <= n; ++i)dis[i] = inf;            cnt = 0,sum = 0;            for(int i = 0,l = G1.size(); i < l; ++i)            {                cnt++;                q.push_back(G1[i]);                dis[G1[i]] = 0;                vis[G1[i]] = 1;            }            spfa();            for(int i = 0,l = G0.size(); i < l; ++i)ans = min(ans,dis[G0[i]]);        }        printf("Case #%d: %I64d\n",++ca,ans);    }    return 0;}