1.题目链接。给定的一张图,有三个人A,B,C,和两个集合s1,s2.A会等概率的在集合s1中的点出现,B会等概率的在集合s2中的点出现,C会等概率的出现在图上的任意一个点。现在A,B,C要在图中的某个点集合,问他们所走过的最短路程的期望是多少?
2.在图中新建一个点(n+1),然后定义个点到这个点的距离就是A,B所在点到这个点距离最短距离之和。然后C点到这个点的每一条最短路就对答案有贡献。所以枚举s1,s2集合,对于每一种情况,新建图之后跑最短路。但是这里很特殊的一点是,每个边的边权都是1,那么可以用BFS+双队列优化掉dij的log,这样就可以A掉该题。
using namespace std;
ll __gcd(ll a, ll b)
{
return !b ? a : __gcd(b, a % b);
}
struct dijnode {
int d, u;
dijnode(int d = 0, int u = 0) :d(d), u(u) {}
};
struct graph {
static const int maxn = 1e5 + 5;
static const int maxm = 2e5 + 5;
struct star {
int v, w, nex;
star(int v = 0, int w = 0, int nex = 0) :v(v), w(w), nex(nex) {}
}edge[maxm];
int head[maxn], tot, n;
int d[maxn];
void init(int _n) {
n = _n;
tot = -1;
memset(head, -1, (n + 1) * sizeof(head[0]));
}
void add_edge(int u, int v, int w) {
edge[++tot] = star(v, w, head[u]);
head[u] = tot;
}
void short_path(queue<dijnode>& q2, int s, int* dist) {//short path
queue<dijnode>q1;// dis and vert
dist[s] = 0;
q1.push(dijnode(dist[s], s));
while (!q1.empty() || !q2.empty())
{
dijnode nd;
if (q1.empty()) nd = q2.front(), q2.pop();
else if (q2.empty()) nd = q1.front(), q1.pop();
else if (q1.front().d < q2.front().d) nd = q1.front(), q1.pop();
else nd = q2.front(), q2.pop();
if (nd.d != dist[nd.u])continue;
int u = nd.u;
for (int i = head[u]; ~i; i = edge[i].nex)
{
int v = edge[i].v, w = edge[i].w;
if (dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
q1.push(dijnode(dist[v], v));
}
}
}
}
}g1;
int n, m;
const int maxn = 1e5 + 55;
int d1[20][maxn], d2[20][maxn];
vector<int> vec[maxn];
long long solve(int p1, int p2) {
queue<dijnode> q;
int mx = 0;
/*
vec数组保存的时 vec[x]=i.距离为x的点有哪些???
*/
for (int i = 1; i <= n; i++)
{
vec[d1[p1][i] + d2[p2][i]].push_back(i);
g1.d[i] = d1[p1][i] + d2[p2][i];
mx = max(mx, g1.d[i]);
}
for (int i = 0; i <= mx; i++) {
for (int x : vec[i]) q.push(dijnode{ d1[p1][x] + d2[p2][x],x });
}
for (int i = 1; i <= n; i++) vec[d1[p1][i] + d2[p2][i]].clear();
g1.short_path(q, n + 1, g1.d);
long long sum = 0;
for (int i = 1; i <= n; i++) sum += g1.d[i];
return sum;
}
int main() {
int t;
scanf("%d", &t);
for (int ti = 1; ti <= t; ti++) {
scanf("%d%d", &n, &m);
g1.init(n + 1);
for (int i = 0; i < m; i++) {
int u, v; scanf("%d%d", &u, &v);
g1.add_edge(u, v, 1);
g1.add_edge(v, u, 1);
}
int s1; scanf("%d", &s1);
for (int i = 0; i < s1; i++)
{
int v1;
scanf("%d", &v1);
queue<dijnode> q;
for (int j = 1; j <= n; j++) d1[i][j] = 2e9;
//求出v1到 1-n的最短路,保存在d1[i]这个数数组里
g1.short_path(q, v1, d1[i]);
}
int s2; scanf("%d", &s2);
for (int i = 0; i < s2; i++) {
int v2; scanf("%d", &v2);
queue<dijnode> q;
for (int j = 1; j <= n; j++) d2[i][j] = 2e9;
g1.short_path(q, v2, d2[i]);
}
long long sum = 0;
for (int i = 0; i < s1; i++)
{
for (int j = 0; j < s2; j++)
{
sum += solve(i, j);
}
}
long long fenmu = 1ll * s1 * s2 * n;
long long gcd = __gcd(sum, fenmu);
printf("Case #%d: %lld/%lld\n", ti, sum / gcd, fenmu / gcd);
}
}