hdu6166 Senior Pan

Senior Pan

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

Problem Description
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
Source
题目大意:给定一个n个点m条边的有向带权图,其中有k个特殊点,求这k个特殊点之间两两最短路的最小值。
分析:没做过这类题根本想不到.
   因为是求两两最短路的最小值,可以考虑把dijkstra变成多源的,也就是把这k个特殊点分成两组,一组当作源点,一组当作汇点,因为dijkstra算法每次找距离最小的出来扩展嘛,那么作为源点的一组最先被扩展到的距离就是这次dijkstra算法应该返回的答案.
   但是怎样分组才能不遗漏的计算完呢?
   考虑一种神奇的分组方式--二进制分组.将k个点的编号转化成二进制数.如果第i位1则当作源点,否则当作汇点,然后交换两组再来一次dijkstra.这样一定会考虑所有的组合方式.why?两个不同的编号,必然在二进制上有一位不同.这一位的不同将它们分成两组计算,所以每一组都计算到了,取个min就是答案.
   我认为分类方法可能还有很多,不遗漏是关键.这道题如果能想到把dijkstra变成多源的就基本上做完了.
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;
const int maxn = 100010;
const ll inf = 1e17;

int T,cas,n,vis[maxn],m,head[maxn],to[maxn],nextt[maxn],w[maxn],tot = 1,K,a[maxn],mark[maxn];
ll d[maxn],ans = inf;

struct node
{
    int x;
    ll len;
    bool operator < (const node& a) const {
        return len > a.len;
    }
};
priority_queue<node> q;

void add(int x,int y,int z)
{
    w[tot] = z;
    to[tot] = y;
    nextt[tot] = head[x];
    head[x] = tot++;
}

ll dijkstra()
{
    while (!q.empty())
    {
        node u = q.top();
        q.pop();
        int x = u.x;
        ll len = u.len;
        if (mark[x])
            return len;
        if (vis[x])
            continue;
        vis[x] = 1;
        for (int i = head[x];i;i = nextt[i])
        {
            int v = to[i];
            if (d[v] > d[x] + w[i])
            {
                d[v] = d[x] + w[i];
                node temp;
                temp.x = v;
                temp.len = d[v];
                q.push(temp);
            }
        }
    }
    return inf;
}

void solve()
{
    for (int i = 0; i < 20; i++)
    {
        while (!q.empty())
            q.pop();
        memset(vis,0,sizeof(vis));
        memset(mark,0,sizeof(mark));
        memset(d,127/3,sizeof(d));
        for (int j = 1; j <= K; j++)
        {
            if ((1 << i) & a[j])
                mark[a[j]] = 1;
            else
            {
                node temp;
                temp.x = a[j];
                temp.len = 0;
                d[a[j]] = 0;
                q.push(temp);
            }
        }
        ans = min(ans,dijkstra());
        memset(vis,0,sizeof(vis));
        memset(mark,0,sizeof(mark));
        memset(d,127/3,sizeof(d));
        while (!q.empty())
            q.pop();
        for (int j = 1; j <= K; j++)
        {
            if ((1 << i) & a[j])
            {
                node temp;
                temp.len = 0;
                temp.x = a[j];
                d[a[j]] = 0;
                q.push(temp);
            }
            else
                mark[a[j]] = 1;
        }
        ans = min(ans,dijkstra());
    }
}

int main()
{
    scanf("%d",&T);
    while (T--)
    {
        ans = inf;
        tot = 1;
        memset(head,0,sizeof(head));
        scanf("%d%d",&n,&m);
        for (int i = 1; i <= m; i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
        }
        scanf("%d",&K);
        for(int i = 1; i <= K; i++)
            scanf("%d",&a[i]);
        solve();
        printf("Case #%d: %lld
",++cas,ans);
    }

    return 0;
}
原文地址:https://www.cnblogs.com/zbtrs/p/8448376.html