hdu 6166 Senior Pan

http://acm.hdu.edu.cn/showproblem.php?pid=6166

 

题意:

给出一张无向图,给定k个特殊点

求这k个特殊点两两之间的最短路

 

二进制分组

枚举一位二进制位

这一位为1的放到起点集合

这一位为0的放到终点集合

跑一遍两个集合间的最短路

因为是有向图,反过来再跑一遍

 

正确性分析:

设最优解是x和y间的最短路

若x和y被分在了两个不同的集合,那么两个集合的最短路就是x和y的最短路

而任意两个点至少有一位二进制不同

所以一定会有x和y分在两个不同集合的时候

 

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 100001

typedef long long LL;

int n,k;

int front[N],to[N],nxt[N],val[N],tot;

int point[N];

struct node
{
    int id;
    LL dis;

    node(int id_=0,LL dis_=0):id(id_),dis(dis_){}

    bool operator < (node p) const
    {
        return dis>p.dis;
    }
};
priority_queue<node>q;

bool End[N],vis[N];

LL dis[N];
LL ans;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}

void add(int u,int v,int w)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w;
}

void dijkstra()
{
    node now;
    while(!q.empty())
    {
        now=q.top();
        q.pop();
        if(vis[now.id]) continue;
        vis[now.id]=true;
        for(int i=front[now.id];i;i=nxt[i])
            if(dis[now.id]+val[i]<dis[to[i]])
            {
                dis[to[i]]=dis[now.id]+val[i];
                if(End[to[i]]) ans=min(ans,dis[to[i]]);
                else q.push(node(to[i],dis[to[i]]));
            }
    }
}


void solve()
{
    int S,bit;
    for(S=1;(1<<S)-1<k;++S);
    for(int j=1;j<=S;++j)
    {
        bit=1<<j-1;
        memset(End,false,sizeof(End));
        memset(vis,false,sizeof(vis));
        memset(dis,63,sizeof(dis));
        for(int i=1;i<=k;++i)
        {
            if(point[i] & bit) q.push(node(point[i],0)),dis[point[i]]=0;
            else End[point[i]]=true;
        }
        dijkstra();
        memset(End,false,sizeof(End));
        memset(vis,false,sizeof(vis));
        memset(dis,63,sizeof(dis));
        for(int i=1;i<=k;++i)
        {
            if(!(point[i] & bit)) q.push(node(point[i],0)),dis[point[i]]=0;
            else End[point[i]]=true;
        }
        dijkstra();
    }
}
    
void clear()
{
    tot=0;
    memset(front,0,sizeof(front));
    ans=1e18;
}

int main()
{
    int T;
    int m;
    int u,v,w;
    read(T);
    for(int t=1;t<=T;++t)
    {
        clear();
        read(n); read(m);
        while(m--)
        {
            read(u); read(v); read(w);
            add(u,v,w);
        }
        read(k);
        for(int i=1;i<=k;++i) read(point[i]);
        solve();
        printf("Case #%d: %I64d\n",t,ans);
    }
}

 

posted @ 2018-02-07 15:19  TRTTG  阅读(183)  评论(0编辑  收藏  举报