1. 程式人生 > >HDU 5521 Meeting (建圖技巧+最短路)

HDU 5521 Meeting (建圖技巧+最短路)

題意:給一些集合,集合裡的任意兩點可以花費某一時間titi到達
有兩人分別在11號點和nn號點
兩人同時出發,問在哪一點見面花費的時間最短
輸出最短時間和見面的點(如果有多個點從小到大輸出多個)

思路:因為集合太大,不可以把每個集合的所有點建邊,我們引入m個虛擬的點,每個集合的點連線引入的點,然後集合的點向虛擬的點建一條正常權值的邊,再建一條反向邊,權值為0.這樣子建邊的複雜度從n2n^2變成了2n2n.
然後只要跑正反兩遍dij,然後遍歷尋找一個最優的點就行了.

#include <bits/stdc++.h>
#define eps 1e-8
#define INF 0x3f3f3f3f3f3f3f3f
#define PI acos(-1) #define lson l,mid,rt<<1 #define rson mid+1,r,(rt<<1)+1 #define CLR(x,y) memset((x),y,sizeof(x)) #define fuck(x) cerr << #x << "=" << x << endl using namespace std; typedef long long ll; typedef unsigned long long ull; const int seed = 131; const
int maxn = 30e5 + 5; const int mod = 1e9 + 7; struct node { int v, w, nxt; node() {} node(int v, int w): v(v), w(w) {} bool operator <(const node &a)const { return w > a.w; } } e[maxn]; int tot, head[maxn]; void add_edge(int u, int v, int w) { e[tot].v = v;
e[tot].w = w; e[tot].nxt = head[u]; head[u] = tot++; } int T, n, m; int a[maxn]; bool vis[maxn]; ll dis[3][maxn]; int DIS[maxn]; void dij(int start, int id) { for (int i = 0; i <= n + m; i++) { dis[id][i] = INF; vis[i] = 0; } priority_queue<node>q; dis[id][start] = 0; q.push(node(start, dis[id][start])); while (!q.empty()) { int u = q.top().v; q.pop(); if (vis[u]) continue; vis[u] = 1; for (int i = head[u]; ~i; i = e[i].nxt) { int v = e[i].v; if (dis[id][v] > dis[id][u] + e[i].w) { dis[id][v] = dis[id][u] + e[i].w; q.push(node(v, dis[id][v])); } } } } int main() { scanf("%d", &T); for (int cas = 1; cas <= T; cas++) { CLR(head, -1); tot = 0; scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { int val, num; scanf("%d%d", &val, &num); for (int j = 1; j <= num; j++) { scanf("%d", &a[j]); add_edge(a[j], n +i, val); add_edge(n + i, a[j], 0); } } dij(1, 1); dij(n, 2); ll MIN = INF; vector<ll>v; v.clear(); for (int i = 1; i <= n; i++) { ll maxx = max(dis[1][i], dis[2][i]); if (maxx < MIN) { MIN = maxx; v.clear(); v.push_back(i); } else if (maxx == MIN) { v.push_back(i); } } printf("Case #%d: ", cas); if (MIN == INF) printf("Evil John\n"); else { printf("%d\n", MIN); int cnt=v.size(); for (int i = 0; i < cnt; i++) { printf("%d%c", v[i], i == cnt - 1 ? '\n' : ' '); } } } return 0; }