最短路
我的构图方式是:
将每个集合也抽象成一个点,将集合中的每个点向集合连一条权值为t的有向边,集合向其中的每个点连一条权值为0的有向边,这样 以1和n为起点各做一遍最短路。
枚举中间点便可以得到最后答案了。
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
struct Edge
{
int v;
long long t;
};
const int MAXN = 100005;
const int MAXM = 1000005;
const long long INF = 1000000000000010LL;
const int MAXP = MAXM + MAXN;
int n, m, cnt;
int pre[MAXM*2], hd[MAXP];
bool inq[MAXP];
long long ds[MAXP], dt[MAXP];
Edge e[MAXM*2];
vector<int> ansV;
void addEdge(int u, int v, long long t)
{
pre[cnt] = hd[u];
hd[u] = cnt;
e[cnt].v = v;
e[cnt].t = t;
cnt++;
}
int main()
{
int T; scanf("%d", &T);
for (int kk = 1; kk <= T; kk++)
{
//input and initialize
cnt = 0;
scanf("%d%d", &n, &m);
memset(hd, -1, sizeof(hd));
for (int i = 1; i <= m; i++)
{
long long tmp;
int num;
scanf("%lld%d", &tmp, &num);
for (int j = 0; j < num; j++)
{
int v; scanf("%d", &v);
addEdge(v, n + i, tmp);
addEdge(n + i, v, 0LL);
}
}
//spfa-s
memset(inq, false, sizeof(inq));
fill(ds, ds + MAXP, INF);
queue<int> q;
q.push(1); inq[1] = true; ds[1] = 0LL;
while (!q.empty())
{
int u = q.front(); q.pop();
int now = hd[u];
while (now != -1)
{
const Edge &ee = e[now];
if (ds[u] + ee.t < ds[ee.v])
{
ds[ee.v] = ds[u] + ee.t;
if (!inq[ee.v])
{
inq[ee.v] = true;
q.push(ee.v);
}
}
now = pre[now];
}
inq[u] = false;
}
//spfa-t
memset(inq, false, sizeof(inq));
fill(dt, dt + MAXP, INF);
while (!q.empty()) q.pop();
q.push(n); inq[n] = true; dt[n] = 0LL;
while (!q.empty())
{
int u = q.front(); q.pop();
int now = hd[u];
while (now != -1)
{
const Edge &ee = e[now];
if (dt[u] + ee.t < dt[ee.v])
{
dt[ee.v] = dt[u] + ee.t;
if (!inq[ee.v])
{
inq[ee.v] = true;
q.push(ee.v);
}
}
now = pre[now];
}
inq[u] = false;
}
//find the ans & output
long long ans = INF;
for (int i = 1; i <= n; i++)
{
if (max(ds[i], dt[i]) < ans) ans = max(ds[i], dt[i]);
}
ansV.clear();
if (ans != INF)
for (int i = 1; i <= n; i++)
{
if (max(ds[i], dt[i]) == ans) ansV.push_back(i);
}
printf("Case #%d: ", kk);
if (ans == INF) printf("Evil John\n");
else
{
printf("%lld\n", ans);
for (int i = 0; i < ansV.size(); i++)
{
if (i) printf(" ");
printf("%d", ansV[i]);
}
printf("\n");
}
}
return 0;
}