HDU 6166

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

题意:给你一幅有向图,选取 K 个点,k 个点任意二点做最短路,输出最小值。

题解:根据k个点某一位上的二进制是 0 或是 1 ,分为二个集合,一个集合为源点,另一个集合为汇点。

     最小值其实就是 k 个点中某二个点的最短路,将这二个点分别放入一个集合,剩余的 k-2 个点放任意集合即可。

     根据某一位上的二进制划分,可以将任意二点分开。

   多源多汇点求最短路。由于二进制的位数最多 20 位,所以做 20 次dijkstra即可。

   由于这是有向图,分点的时候源点、汇点调换一下。

     这里的边用链式向前星存储,dijkstra用优先队列优化。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<queue> 
#define oo 0x3f3f3f3f 
using namespace std;
const int MAXN = 100000+10;
struct node
{
    int b, e, w;
    int next;
}edge[MAXN];
struct no
{
    int e, w;
    no(){
    }
    no(int e, int w):e(e), w(w){
    }
    bool operator < (const no aa)const
    {
        return w > aa.w;
    }
};
int head[MAXN];
int a[MAXN];
bool ise[MAXN];
int grap[MAXN];
priority_queue<no> que;
int dij()
{
    while(!que.empty())
    {
        no nod = que.top();
        que.pop();
        if(ise[nod.e]) return nod.w;
        for(int i = head[nod.e]; ~i; i = edge[i].next)
        {
            if(grap[edge[i].e] > grap[nod.e] + edge[i].w)
            {
                grap[edge[i].e] = grap[nod.e] + edge[i].w;
                que.push( no(edge[i].e, grap[edge[i].e]) );
            }
        }
    }
    return oo;
}
void addedge(int x, int y, int z, int i)
{
    edge[i].b = x;
    edge[i].e = y;
    edge[i].w = z;
    edge[i].next = head[x];
    head[x] = i;
}
void init()
{
    memset(ise, false, sizeof(ise));
    memset(grap, oo, sizeof(grap));
    while(!que.empty()) que.pop();
}
int main (void)
{
    ios::sync_with_stdio(false);
    int t; cin >> t;
    int Case = 0;
    while(t--)
    {
        int n, m;
        cin >> n >> m;
        memset(head, 0xffff, sizeof(head));
        for(int i = 1; i <= m; i++)
        {
            int x, y, z;
            cin >> x >> y >> z;
            addedge(x, y, z, i);
        }
        int k; cin >> k;
        for(int i = 1; i <= k; i++)
        {
            cin >> a[i];
        }
        int ans = oo;
        for(int j = 0; j <= 20; j++ )
        {
            init();
            for(int i = 1; i <= k; i++)
            {
                if(a[i]&(1<<j))
                {
                    ise[a[i]] = true; 
                }
                else
                {
                    que.push(no(a[i], 0));
                    grap[a[i]] = 0; 
                }
            }
            ans = min(ans, dij());
            
            init();
            for(int i = 1; i <= k; i++)
            {
                if(a[i]&(1<<j))
                {
                    que.push(no(a[i], 0));
                    grap[a[i]] = 0; 
                }
                else
                { 
                    ise[a[i]] = true; 
                }
            }
            ans = min(ans, dij());
        }
        cout << "Case #" << ++Case << ": " << ans << endl;
    }
}
/*
1
2 1
1 2 1
2
1 2
*/
原文地址:https://www.cnblogs.com/lkcc/p/7436246.html