[hdu 6166 Senior Pan]Dijkstra+概率随机

[hdu 6166 Senior Pan]Dijkstra+概率随机

分类:Dijkstra probability data structure

1. 题目链接

[hdu 6166Senior Pan]

2. 题意描述

有一个 n 个顶点m点边的有向带权图。已知从其中选出的 K 个点。在这K个点中选出两个点,要使得他们的最短路最小。
数据范围: 15 , 1n,m100000 , 2Kn 1100000

3. 解题思路

方法一:假设最终的答案对应的两个端点为 s,t , 将K个点分成两半,那么,有四种情况:
1. s,t 在前一半;
2. s,t 在后一半;
3. s 在第一半t在第二半;
4. t 在第一半s在第二半。
如果是Solution 3或者Solution 4, 只需要将一个超级源点连接所有前一半的点,边权为0,跑一遍Dijkstra。就可以求出前一半点集到后一半点集的最短路,这样就可以得到答案了。
如果是Solution 1或者Solution 2, 按照上面的做法是得不到答案的。
这样,一次Dijkstra跑出答案的概率为 12 ,那么重复 x 次,成功的概率为112k ,当 x=20 ,可以依概率接近1求出答案。
这题,随机技巧性很强。
方法二:只需要一次Dijkstra就可以了。选一个超级源点,并连接所有 K 个点,权值为0。Dijkstra算法中,每次枚举边的同时,顺便更新答案就好了。感觉这个挺容易写错的。

Tips:将超级源点连接到点集V,并不一定非得新建一个顶点,只需要将点集 V <script type="math/tex" id="MathJax-Element-22">V</script>中所有点一起放入队列,并将到该点的最短路径置为0就好了。

4. 实现代码

/**方法一**/
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <ctime>
#include <cmath>
#include <cctype>
#include <cstdio>
#include <string>
#include <cstring>
#include <cassert>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long LL;
typedef long double LB;
typedef unsigned int uint;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef pair<LB, LB> PLB;
typedef vector<int> VI;

const int INF = 0x3f3f3f3f;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;
const long double PI = acos(-1.0);
const long double eps = 1e-4;
void debug() { cout << endl; }
template<typename T, typename ...R> void debug (T f, R ...r) { cout << "[" << f << "]"; debug (r...); }
template<typename T> inline void umax(T &a, T b) { a = max(a, b); }
template<typename T> inline void umin(T &a, T b) { a = min(a, b); }
template <typename T> inline bool scan_d (T &ret) {
    char c; int sgn;
    if (c = getchar(), c == EOF) return 0; //EOF
    while (c != '-' && (c < '0' || c > '9') ) if((c = getchar()) == EOF) return 0;
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return 1;
}
template<typename T> void print(T x) {
    static char s[33], *s1; s1 = s;
    if (!x) *s1++ = '0';
    if (x < 0) putchar('-'), x = -x;
    while(x) *s1++ = (x % 10 + '0'), x /= 10;
    while(s1-- != s) putchar(*s1);
}
template<typename T> void println(T x) { print(x); putchar('\n'); }
template<typename T> T randIntv(T a, T b) { return rand() % (b - a + 1) + a; } /*[a, b]*/

const int MAXN = 100005;
const int MAXE = 100005;

int T, n, m, K;
int a[MAXN]; LL ans;

template<class T>
struct Dijkstra {
    struct Edge {
        T w;
        int v, nxt;
    } E[MAXE << 1];
    typedef pair<T, int> QNode;
    int Head[MAXN], erear;
    T d[MAXN], INF;
    void init() {
        erear = 0;
        memset(Head, -1, sizeof(Head));
    }
    void add_edge(int u, int v, T w) {
        E[erear].v = v;
        E[erear].w = w;
        E[erear].nxt = Head[u];
        Head[u] = erear++;
    }
    T run() {
        memset(d, 0x3f, sizeof(d));
        INF = d[0];
        priority_queue<QNode, vector<QNode>, greater<QNode> >Q;
        for(int i = 1; i <= K / 2; ++i) Q.push(QNode(0, a[i])); d[a[i]] = 0;
        while(!Q.empty()) {
            QNode ftp = Q.top(); Q.pop();
            int u = ftp.second;
            if(ftp.first != d[u]) continue;
            for(int i = Head[u]; ~i; i = E[i].nxt) {
                int v = E[i].v; T w = E[i].w;
                if(d[u] + w < d[v]) {
                    d[v] = d[u] + w;
                    Q.push(QNode(d[v], v));
                }
            }
        }
        T ret = INF;
        for(int i = K / 2 + 1; i <= K; ++i) umin(ret, d[a[i]]);
        return ret;
    }
};
Dijkstra<LL> dij;

int main() {
#ifdef ___LOCAL_WONZY___
    freopen ("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
    int cas = 0, u, v, w;
    scan_d(T);
    while(T --) {
        scan_d(n), scan_d(m);
        dij.init();
        for(int i = 1; i <= m; ++i) {
            scan_d(u), scan_d(v), scan_d(w);
            dij.add_edge(u, v, w);
        }
        scan_d(K);
        for(int i = 1; i <= K; ++i) {
            scan_d(a[i]);
        }
        ans = INFL;
        int times = 20;
        while(times --) {
            random_shuffle(a + 1, a + K + 1);
//            for_each(a + 1, a + K + 1, [](int item) { cout << item << " "; }); puts("");
            umin(ans, dij.run());
        }
        printf("Case #%d: %lld\n", ++cas, ans);
    }
#ifdef ___LOCAL_WONZY___
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // ___LOCAL_WONZY___
    return 0;
}
/**方法二**/
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <ctime>
#include <cmath>
#include <cctype>
#include <cstdio>
#include <string>
#include <cstring>
#include <cassert>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long LL;
typedef long double LB;
typedef unsigned int uint;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef pair<LB, LB> PLB;
typedef vector<int> VI;

const int INF = 0x3f3f3f3f;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;
const long double PI = acos(-1.0);
const long double eps = 1e-4;
void debug() { cout << endl; }
template<typename T, typename ...R> void debug (T f, R ...r) { cout << "[" << f << "]"; debug (r...); }
template<typename T> inline void umax(T &a, T b) { a = max(a, b); }
template<typename T> inline void umin(T &a, T b) { a = min(a, b); }
template <typename T> inline bool scan_d (T &ret) {
    char c; int sgn;
    if (c = getchar(), c == EOF) return 0; //EOF
    while (c != '-' && (c < '0' || c > '9') ) if((c = getchar()) == EOF) return 0;
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return 1;
}
template<typename T> void print(T x) {
    static char s[33], *s1; s1 = s;
    if (!x) *s1++ = '0';
    if (x < 0) putchar('-'), x = -x;
    while(x) *s1++ = (x % 10 + '0'), x /= 10;
    while(s1-- != s) putchar(*s1);
}
template<typename T> void println(T x) { print(x); putchar('\n'); }
template<typename T> T randIntv(T a, T b) { return rand() % (b - a + 1) + a; } /*[a, b]*/

const int MAXN = 100005;
const int MAXE = 100005;

int T, n, m, K;
int a[MAXN]; LL ans;
bool flag[MAXN];

template<class T>
struct Dijkstra {
    struct Edge {
        T w;
        int v, nxt;
    } E[MAXE << 1];
    typedef tuple<T, int, int> QNode;
    int Head[MAXN], erear;
    T d[MAXN], INF;
    void init() {
        erear = 0;
        memset(Head, -1, sizeof(Head));
    }
    void add_edge(int u, int v, T w) {
        E[erear].v = v;
        E[erear].w = w;
        E[erear].nxt = Head[u];
        Head[u] = erear++;
    }
    T run() {
        memset(d, 0x3f, sizeof(d));
        INF = d[0];
        priority_queue<QNode, vector<QNode>, greater<QNode> >Q;
        for(int i = 1; i <= K; ++i) Q.push(QNode(0, a[i], a[i])), d[a[i]] = 0;
        T ret = INF;
        T cost; int u, fu;
        while(!Q.empty()) {
            tie(cost, u, fu) = Q.top(); Q.pop();
            if(cost != d[u]) continue;
            for(int i = Head[u]; ~i; i = E[i].nxt) {
                int v = E[i].v; T w = E[i].w;
                if(flag[v] && v != fu) umin(ret, d[u] + w); /**注意v!=fu的条件**/
                if(d[u] + w < d[v]) {
                    d[v] = d[u] + w;
                    Q.push(QNode(d[v], v, flag[v] ? v : fu));
                }
            }
        }
        return ret;
    }
};
Dijkstra<LL> dij;

int main() {
#ifdef ___LOCAL_WONZY___
    freopen ("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
    int cas = 0, u, v, w;
    scan_d(T);
    while(T --) {
        scan_d(n), scan_d(m);
        dij.init();
        for(int i = 1; i <= m; ++i) {
            scan_d(u), scan_d(v), scan_d(w);
            dij.add_edge(u, v, w);
        }
        scan_d(K);
        memset(flag, false, sizeof(flag));
        for(int i = 1; i <= K; ++i) {
            scan_d(a[i]);
            flag[a[i]] = true;
        }
        ans = dij.run();
        printf("Case #%d: %lld\n", ++cas, ans);
    }
#ifdef ___LOCAL_WONZY___
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // ___LOCAL_WONZY___
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值