HDU 6166 Senior Pan

HDU 6166 Senior Pan

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
	一个图,然后指定几个点,问这些点之间所有组合的起点终点中最短的一条路径是什么。
	多源多汇,比较容易想到建总源点和总汇点。之间跑源点汇点的最短路。但是这样问题很多。看来别人的操作后,随机把k个点分成两组。然后把两组分别连源点和汇点,权值0.一次最短路。如果答案的两个点被你分到了两个集合,那么答案就出来了。由于答案被分到两个集合的概率是0.5.做n次期望能有n/2次能获得答案。那么直接来个十几次随机。AC概率就很大了。
	官方是按某个二进制位划分,因为来个数字不同,必有某位二进制是不同的。那么对二进制的每一位的0,1分集合就能包含所有划分集合。
/**
令人窒息的随机算法,通过多次随机获得较高的AC概率

官方解法是,两个数字不同,那么肯定有一位二进制是不同的。

所以可以通过枚举二进制位的仿佛枚举所有集合对

*/
#include <bits/stdc++.h>

using namespace std;
const int MAXN = 1e5 + 10;
typedef long long LL;
const LL INF = 0x3F3F3F3F3F3F3F3F;

int n, m, k, first[MAXN], sign, arr[MAXN];

struct Input {
    int u, v;
    LL w;
} in[MAXN];

struct Edge {
    int to, next;
    LL w;
} edge[MAXN * 4];

void init() {
    memset(first, -1, sizeof(first));
    sign = 0;
}

void add_edge(int u, int v, LL w) {
    edge[sign].to = v;
    edge[sign].w = w;
    edge[sign].next = first[u];
    first[u] = sign++;
}

LL dist[MAXN];

int inq[MAXN];

LL spfa(int s, int t) {
    memset(dist, 0x3F, sizeof(dist));
    memset(inq, 0, sizeof(inq));
    queue<int>que;
    que.push(s);
    inq[s] = 1;
    dist[s] = 0;
    while(!que.empty()) {
        int now = que.front();
        que.pop();
        inq[now] = 0;
        for(int i = first[now]; ~i; i = edge[i].next) {
            int to = edge[i].to;
            LL w = edge[i].w;
            if(dist[to] > dist[now] + w) {
                dist[to] = dist[now] + w;
                if(!inq[to]) {
                    inq[to] = 1;
                    que.push(to);
                }
            }
        }
    }
    return dist[t];
}

LL random() {
    init();
    for(int i = 1; i <= m; i++ ) {
        int u = in[i].u, v = in[i].v, w = in[i].w;
        add_edge(u, v, w);
    }
    for(int i = 1; i <= k; i++ ) {
        int ac = rand() % 2;
        if(ac) {
            add_edge(0, arr[i], 0);
        } else {
            add_edge(arr[i], n + 1, 0);
        }
    }
    return spfa(0, n + 1);
}

int main()
{
    int t;
    scanf("%d", &t);
    srand(unsigned(time(0)));
    for(int cas = 1; cas <= t; cas++ ) {
        scanf("%d %d", &n, &m);
        for(int i = 1; i <= m; i++ ) {
            int u, v, w;
            scanf("%d %d %d", &u, &v, &w);
            in[i].u = u, in[i].v = v, in[i].w = w;
        }
        scanf("%d", &k);
        for(int i = 1; i <= k; i++ ) {
            scanf("%d", &arr[i]);
        }
        int limit = 20;
        LL ans = INF;
        for(int cnt = 1; cnt <= limit; cnt++ ) {
            ans = min(ans, random());
        }
        printf("Case #%d: %lld
", cas, ans);
    }

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