2017 Multi-University Training Contest 9 && HDU 6166 Senior Pan 【最短路+思维】

来源:互联网 发布:淘宝商城入驻 编辑:程序博客网 时间:2024/05/21 10:13


Senior Pan

Time Limit: 12000/6000 MS (Java/Others)    Memory Limit:131072/131072 K (Java/Others)
Total Submission(s): 468    Accepted Submission(s): 163

Problem Description

SeniorPan fails in his discrete math exam again. So he asks Master ZKC to give himgraph theory problems everyday.
The task is simple : ZKC will give Pan a directed graph every time, and selectssome nodes from that graph, you can calculate the minimum distance of everypair of nodes chosen in these nodes and now ZKC only cares about the minimumamong 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 TestCases.1≤T≤5.Then T Test Cases, for each Test Cases, the first line contains twointegers n,m representing the number of nodes and the number ofedges.1≤n,m≤100000
Then m lines follow. Each line contains three integers
xi,yi representing anedge, andvi representing its length.1≤xi,yi≤n,1≤vi≤100000
Then one line contains one integer K, the number of nodes that Master Dongselects out.1≤K≤n
The following line contains K unique integers
ai, the nodes thatMaster 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

 

【题意】


给出一个n个点,m条边的有向图,从这n个点中选出k个,现在我们需要从这k个点中选出一个点作为起点,一个点作为终点,使得从起点到终点的距离是所有选择中最小的。


【思路】


显然,我们需要考虑这k个点两两之间的距离,取最小值,但这样做时间不允许,我们考虑优化。


我们可以把这k个点分成两个集合,一个集合作为起点,一个集合作为终点,那么我们要求的便转化为了多起点多终点的最短路,这只需要建立一个超级源点和超级汇点,然后跑一遍最短路即可。


但现在问题是该如何把k个点分成两个集合,使得所有情况都不被遗漏呢?(如果随意分的话,也许原来是最优解的两个点被分到了同一集合,显然结果就不对了)


我们考虑对这k个点的编号进行二进制分解。


首先有一个显然的结论:任意两个不同的数,它们的二进制数总有一位是不同的。


那只要我们枚举每一个二进制位,根据该位是否为1,分成两个集合,根据这个结论,总会有一种分法使某两个点不在同一集合内。


由于只要跑2*logn次最短路,时间复杂度为O(2*nlognlogn)。


(据说还可以用随机化分集合,分得越多出错概率越小,分个二三十次就能得到正解。。。)



#include <cstdio>#include <queue>#include <cstring>#include <algorithm>using namespace std;#define mst(a,b) memset((a),(b),sizeof(a))#define rush() int T;scanf("%d",&T);while(T--)typedef long long ll;const int maxn = 100005;const ll mod = 1e9+7;const int INF = 0x3f3f3f3f;const double eps = 1e-9;int n,m,k,cnt,Max;int a[maxn];int dis[maxn];int color[maxn];bool vis[maxn];int head[maxn];struct point{    int u,v,w;}p[maxn];struct node{    int v,w,next;}e[maxn];void add(int u,int v,int w){    e[cnt].v=v;    e[cnt].w=w;    e[cnt].next=head[u];    head[u]=cnt++;}void build()            //建图{    cnt=0;    mst(head,-1);    for(int i=0;i<m;i++)    {        int u=color[p[i].u];        int v=color[p[i].v];        add(u,v,p[i].w);    }}int spfa(int s,int t){    mst(dis,0x3f);    mst(vis,0);    queue<int>q;    q.push(s);    dis[s]=0;    vis[s]=1;    while(q.size())    {        int u=q.front();        q.pop();        vis[u]=0;        for(int i=head[u];~i;i=e[i].next)        {            int v=e[i].v;            int w=e[i].w;            if(w+dis[u]<dis[v])            {                dis[v]=dis[u]+w;                if(vis[v]==0)                {                    vis[v]=1;                    q.push(v);                }            }        }    }    return dis[t];}int solve(){    for(int i=0;i<=n+1;i++)    {        color[i]=i;    }    int ss=0,tt=n+1;                    //建立超级源点,超级汇点    int ans=INF;    for(int i=0;(1<<i)<=Max;i++)        //枚举二进制位    {        for(int j=0;j<k;j++)            //把k个点分成两个集合        {            if((a[j]>>i)&1) color[a[j]]=ss;            else color[a[j]]=tt;        }        build();        ans=min(ans,spfa(ss,tt));       //由于都是有向边,所以需要正向反向跑两次        ans=min(ans,spfa(tt,ss));    }    return ans;}int main(){    int cas=1;    rush()    {        scanf("%d%d",&n,&m);        for(int i=0;i<m;i++)        {            scanf("%d%d%d",&p[i].u,&p[i].v,&p[i].w);        }        scanf("%d",&k);        Max=0;        for(int i=0;i<k;i++)        {            scanf("%d",&a[i]);            Max=max(Max,a[i]);        }        int ans=solve();        printf("Case #%d: %d\n",cas++,ans);    }    return 0;}







阅读全文
0 0
原创粉丝点击