Live2d Test Env

HDU - 6166:Senior Pan(顶点集合最短路&二进制分组)

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.

InputThe 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 ,i  xi,yi representing an edge, and i  vi representing its length.1≤,i  xi,yi ≤n,1≤i  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 i  ai , the nodes that Master Dong selects out.1≤i  ai ≤n,i  ai !=aj
OutputFor every Test Case, output one integer: the answerSample 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

题意:给定有向图,然后给一个集合,让你在这个集合选一个作为起点,一个作为终点,其最短路最小。

思路:上次做过树上最大收益(边权为花费,顶点有价格,求最大差价),每个点连接汇点,权值为负价;每个点连接源点,权值为正价。然后跑最长路。

此题也是一样的套路,但是起点和终点不能是同一点,所以我们需要分组。

 

这里分组可以随机20次;也可以用“二进制分组法”。:

 

举例说明,将1 2 3 4 进行分组,四个数的二进制形式为: 001 010 011 100
第一次看第0位为1的数,那么A={1,3},B={2,4}
第一次看第1位为1的数,那么A={2,3},B={1,4}
第一次看第2位为1的数,那么A={4},B={1,2,3}
可以看出,任意一对数字,都至少有一次机会不在同一组中。

由于是有向图,还得反过来来一次。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
using namespace std;
const ll inf=1234567645893456783;
const int maxn=100010;
int S,T,Laxt[maxn],Next[maxn];
int in[maxn],To[maxn],Len[maxn],a[maxn],cnt;
ll dis[maxn],ans;
vector<int>G[maxn];
void add(int u,int v,int w){
    Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; Len[cnt]=w;
}
void SPFA()
{
    rep(i,S,T) dis[i]=inf,in[i]=0;
    dis[S]=0; queue<int>q;
    q.push(S); in[S]=1;
    while(!q.empty()){
        int u=q.front(); q.pop();
        for(int i=Laxt[u];i;i=Next[i]){
            int v=To[i]; if(dis[u]+Len[i]<dis[v]) {
                dis[v]=dis[u]+Len[i];
                if(!in[v]) in[v]=1,q.push(v);
            }
        }
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i]; if(dis[u]<dis[v]) {
                dis[v]=dis[u];
                if(!in[v]) in[v]=1,q.push(v);
            }
        }
        in[u]=0;
    }
    ans=min(ans,dis[T]);
}
int main()
{
    int C,Cas=0,N,M,tot,u,v,w;
    scanf("%d",&C);
    while(C--){
        scanf("%d%d",&N,&M); T=N+1; ans=inf;
        rep(j,S,T) Laxt[j]=0; cnt=0;
        rep(i,1,M) scanf("%d%d%d",&u,&v,&w),add(u,v,w);
        scanf("%d",&tot);
        rep(i,1,tot) scanf("%d",&a[i]);
        rep(i,0,17){
            rep(j,S,T) G[j].clear();
            rep(j,1,tot)
              if(j&(1<<i)) G[S].push_back(a[j]);
              else G[a[j]].push_back(T);
            SPFA();
            rep(j,S,T) G[j].clear();
            rep(j,1,tot)
              if(j&(1<<i)) G[a[j]].push_back(T);
              else G[S].push_back(a[j]);
            SPFA();
        }
        printf("Case #%d: %lld\n",++Cas,ans);
    }
    return 0;
}

 

posted @ 2018-10-21 09:26  nimphy  阅读(516)  评论(0编辑  收藏  举报