校内训练0611 最近点对

【题目大意】

n个点m条边带权无向图,求前k个点之间的最短距离,多组数据。

T<=10,n<=50000,k<=1000

【题解】

首先暴力O(Tknlogn)是过不了的。。。

考虑比暴力优秀一点的做法?随机化!

我们随机一半的点分在A,一半的点分在B,S向A中点连边,边权0;B中点想T连边,边权0.

每次求S->T的最短路对应的就是A点集->B点集的最短路。

多随机几次就行了。

标程0.5s,标准时限1.5s

本机标程2s,仿照开3倍时限,开到6s,过了。。

复杂度O(T*nT*nlogn),nT为随机次数,我取了5,本机太慢了qwq

# include <queue>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 4e5 + 10;
const int mod = 1e9+7, INF = 1e9;

# define RG register
# define ST static

int n, m, K, S, T, id[M], old[M];
int head[M], nxt[M], to[M], w[M], tot=0;
inline void add(int u, int v, int _w) {
     ++tot; nxt[tot] = head[u]; head[u] = tot;
    to[tot] = v; w[tot] = _w;
}
inline void adde(int u, int v, int _w) {
    add(u, v, _w); add(v, u, _w);
}

struct pa {
    int x, dis;
    pa() {}
    pa(int x, int dis) : x(x), dis(dis) {}
    friend bool operator < (pa a, pa b) {
        return a.dis > b.dis;
    }
};

int d[M]; 
bool vis[M]; 
priority_queue< pa > q;

inline int dijkstra() {
    for (int i=1; i<=T; ++i) d[i] = INF, vis[i] = 0; 
    q.push(pa(S, 0)); d[S] = 0;
    while(!q.empty()) {
        pa t = q.top(); q.pop();
        if(vis[t.x]) continue;
        vis[t.x] = 1; 
        for (int i=head[t.x]; i; i=nxt[i]) {
            if(d[to[i]] > d[t.x] + w[i]) {
                d[to[i]] = d[t.x] + w[i];
                q.push(pa(to[i], d[to[i]]));
            }
        }
    }
    return d[T];
}

inline void sol() {
    cin >> n >> m >> K;
    for (int i=1, u, v, _w; i<=m; ++i) { 
        scanf("%d%d%d", &u, &v, &_w);
        adde(u, v, _w); 
    }
    for (int i=1; i<=K; ++i) id[i] = i; 
    for (int i=1; i<=K; ++i) old[i] = head[i]; 
    int nTOT = tot; S = n+1, T = n+2;
    int ans = INF;
    for (int Test=1; Test<=5; ++Test) {
        random_shuffle(id+1, id+K+1);
        for (int i=1; i<=K/2; ++i) adde(S, id[i], 0);
        for (int i=K/2+1; i<=K; ++i) adde(id[i], T, 0);
        ans = min(ans, dijkstra()); 
        for (int i=1; i<=K; ++i) head[i] = old[i];
        tot = nTOT; head[S] = head[T] = 0; 
    }
    cout << ans << endl; 
    tot = 0;
    for (int i=1; i<=n+2; ++i) head[i] = 0; 
}

int main() {
    freopen("nearest.in", "r", stdin);
    freopen("nearest.out", "w", stdout); 
    int T; cin >> T;
    while(T--) sol();
    return 0;
}
View Code

 

posted @ 2017-06-13 20:30  Galaxies  阅读(782)  评论(4编辑  收藏  举报