题意:
给出n个点的一个图,每个点属于一个块或者几个块,保证第i块内的点都可以用时间ti互相到达,现在A在点1,B在点n,他们要找一个点开会,会议必须要双方都到场才能开始,问会议最快能需要多长时间能开始,另外按升序输出保证时间最小的可选择的开会的点的序号。
思路:
主要是考建图,暴力建图是不行的,这里每个块建立一个中转点,让中转点和该块内的所有点都连上长度为t的边,这样每次从一个点到达块内的另一个点就需要2*t的时间,最后的答案/2即可。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int MAXN = 2222222;
const int INF = 0x3f3f3f3f;
struct Edge {
int from, to;
long long dist;
};
struct SPFA {
int n, m;
vector <Edge> edges;
vector <int> G[MAXN];
bool vis[MAXN];
long long d[MAXN], p[MAXN];
int cnt[MAXN];
void init(int n) {
this -> n = n;
for (int i = 1; i <= n; i++) G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int dist) {
edges.push_back((Edge) {from, to, dist});
m = edges.size();
G[from].push_back(m - 1);
}
bool solve(int s) {
queue <int> q;
memset (vis, false, sizeof vis);
memset (cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; i++) d[i] = INF;
vis[s] = true; d[s] = 0; cnt[s] = 1; q.push (s);
while (!q.empty ()) {
int u = q.front (); q.pop ();
vis[u] = false;
for (int i = 0; i < (int)G[u].size(); i++) {
Edge& e = edges[G[u][i]];
int v = e.to, w = e.dist;
if (d[v] > d[u] + w) {
d[v] = d[u] + w;
if (!vis[v]) {
vis[v] = true; q.push (v);
if (++cnt[v] > n)
return false;
}
}
}
}
return true;
}
} spfa;
long long t1[MAXN], tn[MAXN];
int main() {
//freopen("in.txt", "r", stdin);
int T, cs = 0;
scanf("%d", &T);
while (T--) {
int n, m;
scanf("%d%d", &n, &m);
spfa.init(n + m);
for (int i = 1; i <= m; i++) {
int t, s, u;
scanf("%d%d", &t, &s);
for (int j = 1; j <= s; j++) {
scanf("%d", &u);
spfa.AddEdge(n + i, u, t);
spfa.AddEdge(u, n + i, t);
}
}
spfa.solve(1);
for (int i = 1; i <= n; i++) t1[i] = spfa.d[i];
spfa.solve(n);
for (int i = 1; i <= n; i++) tn[i] = spfa.d[i];
long long ans = INF;
for (int i = 1; i <= n; i++)
ans = min(ans, max(t1[i], tn[i]));
if (ans >= INF) {
printf("Case #%d: Evil John\n", ++cs);
continue;
}
vector <int> vec;
for (int i = 1; i <= n; i++)
if (max(t1[i], tn[i]) == ans) vec.push_back(i);
printf("Case #%d: %lld\n", ++cs, ans / 2);
for (int i = 0; i < (int)vec.size(); i++)
printf("%d%c", vec[i], i == vec.size() - 1 ? '\n' : ' ');
}
}