HDU 5521 Meeting (建圖技巧+最短路)
阿新 • • 發佈:2018-12-13
題意:給一些集合,集合裡的任意兩點可以花費某一時間到達
有兩人分別在號點和號點
兩人同時出發,問在哪一點見面花費的時間最短
輸出最短時間和見面的點(如果有多個點從小到大輸出多個)
思路:因為集合太大,不可以把每個集合的所有點建邊,我們引入m個虛擬的點,每個集合的點連線引入的點,然後集合的點向虛擬的點建一條正常權值的邊,再建一條反向邊,權值為0.這樣子建邊的複雜度從變成了.
然後只要跑正反兩遍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;
}