Loading [MathJax]/extensions/tex2jax.js

BZOJ2707:「SDOI2012」走迷宫 – 题解

主要思路

这题细节真他妈多。

首先,看到 SCC 大小少于 \(100\) 就可以知道是 DAG DP + Tarjan + 高斯消元了,比较显然。然而实现起来非常麻烦。我们在反图上做 DP 的时候,从 queue 拿出顶点后先高斯消元一波,把环内的、SCC 之间的(也就是之前求出的 \(dp[u]\))一起放到方程组里进行消元即可。细节看代码吧,真的呕了。

代码

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// BZ2707.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e4 + 200, MAX_M = 1001000;
const double eps = 1e-8;
int n, m, phead[MAX_N], rhead[MAX_N], current, start_pt, end_pt, aff[MAX_N], dfn[MAX_N], low[MAX_N], ptot, stk[MAX_N], tail;
int ncnt, outdeg[MAX_N], indeg[MAX_N], pos[MAX_N];
double mat[220][220], f[MAX_N];
bool vis[MAX_N], inst[MAX_N];
vector<int> sccs[MAX_N];
struct edge
{
int to, nxt;
} edges[MAX_M * 3];
void addpath(int *header, int src, int dst)
{
edges[current].to = dst, edges[current].nxt = header[src];
header[src] = current++;
}
void gauss(int siz)
{
for (int i = 1; i <= siz; i++)
{
int key = i;
for (int j = i + 1; j <= siz; j++)
if (fabs(mat[j][i]) > fabs(mat[key][i]))
key = j;
if (fabs(mat[key][i]) <= eps)
continue;
if (key != i)
for (int j = 1; j <= siz + 1; j++)
swap(mat[i][j], mat[key][j]);
double tmp = mat[i][i];
for (int j = i; j <= siz + 1; j++)
mat[i][j] /= tmp;
for (int j = 1; j <= siz; j++)
if (i != j)
{
double rate = mat[j][i];
for (int k = i; k <= siz + 1; k++)
mat[j][k] -= rate * mat[i][k];
}
}
}
void tarjan(int u)
{
dfn[u] = low[u] = ++ptot, inst[u] = true, stk[++tail] = u;
for (int i = phead[u]; i != -1; i = edges[i].nxt)
if (dfn[edges[i].to] == 0)
tarjan(edges[i].to), low[u] = min(low[u], low[edges[i].to]);
else if (inst[edges[i].to])
low[u] = min(low[u], dfn[edges[i].to]);
if (dfn[u] == low[u])
{
ncnt++;
do
{
aff[stk[tail]] = ncnt, sccs[ncnt].push_back(stk[tail]), inst[stk[tail]] = false, pos[stk[tail]] = sccs[ncnt].size();
} while (stk[tail--] != u);
}
}
void output(int siz)
{
for (int i = 1; i <= siz; i++, puts(""))
for (int j = 1; j <= siz + 1; j++)
printf("%.3lf ", mat[i][j]);
}
void processSCC(int id)
{
int siz = sccs[id].size();
memset(mat, 0, sizeof(mat));
for (int idx = 1; idx <= siz; idx++)
{
int u = sccs[id][idx - 1];
for (int i = rhead[u]; i != -1; i = edges[i].nxt)
if (aff[edges[i].to] == aff[u])
{
mat[pos[edges[i].to]][pos[u]] += 1.0 / double(outdeg[edges[i].to]);
mat[pos[edges[i].to]][siz + 1] -= 1.0 / double(outdeg[edges[i].to]);
}
}
for (int idx = 1; idx <= siz; idx++)
{
int u = sccs[id][idx - 1];
mat[idx][siz + 1] -= f[u];
if (u == end_pt)
memset(mat[idx], 0, sizeof(mat[idx]));
mat[idx][idx] -= 1.0;
}
gauss(siz);
for (auto x : sccs[id])
f[x] = mat[pos[x]][siz + 1];
}
void dfs(int u)
{
vis[u] = true;
if (u == end_pt)
return;
for (int i = phead[u]; i != -1; i = edges[i].nxt)
{
if (aff[edges[i].to] != aff[u])
indeg[aff[u]]++;
if (!vis[edges[i].to])
dfs(edges[i].to);
}
}
int main()
{
memset(rhead, -1, sizeof(rhead)), memset(phead, -1, sizeof(phead));
scanf("%d%d%d%d", &n, &m, &start_pt, &end_pt);
for (int i = 1, u, v; i <= m; i++)
scanf("%d%d", &u, &v), addpath(phead, u, v), addpath(rhead, v, u), outdeg[u]++;
for (int i = 1; i <= n; i++)
if (!dfn[i])
tarjan(i);
dfs(start_pt);
for (int i = 1; i <= n; i++)
if (vis[i] && aff[i] != aff[end_pt] && indeg[aff[i]] == 0)
puts("INF"), exit(0);
queue<int> q;
q.push(aff[end_pt]);
while (!q.empty())
{
int u = q.front();
q.pop();
processSCC(u);
if (u == aff[start_pt])
printf("%.3lf\n", fabs(f[start_pt])), exit(0);
for (auto key : sccs[u])
for (int i = rhead[key]; i != -1; i = edges[i].nxt)
if (aff[edges[i].to] != aff[key])
{
f[edges[i].to] += (f[key] + 1.0) / double(outdeg[edges[i].to]);
if (--indeg[aff[edges[i].to]] == 0)
q.push(aff[edges[i].to]);
}
}
puts("INF");
return 0;
}
// BZ2707.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1e4 + 200, MAX_M = 1001000; const double eps = 1e-8; int n, m, phead[MAX_N], rhead[MAX_N], current, start_pt, end_pt, aff[MAX_N], dfn[MAX_N], low[MAX_N], ptot, stk[MAX_N], tail; int ncnt, outdeg[MAX_N], indeg[MAX_N], pos[MAX_N]; double mat[220][220], f[MAX_N]; bool vis[MAX_N], inst[MAX_N]; vector<int> sccs[MAX_N]; struct edge { int to, nxt; } edges[MAX_M * 3]; void addpath(int *header, int src, int dst) { edges[current].to = dst, edges[current].nxt = header[src]; header[src] = current++; } void gauss(int siz) { for (int i = 1; i <= siz; i++) { int key = i; for (int j = i + 1; j <= siz; j++) if (fabs(mat[j][i]) > fabs(mat[key][i])) key = j; if (fabs(mat[key][i]) <= eps) continue; if (key != i) for (int j = 1; j <= siz + 1; j++) swap(mat[i][j], mat[key][j]); double tmp = mat[i][i]; for (int j = i; j <= siz + 1; j++) mat[i][j] /= tmp; for (int j = 1; j <= siz; j++) if (i != j) { double rate = mat[j][i]; for (int k = i; k <= siz + 1; k++) mat[j][k] -= rate * mat[i][k]; } } } void tarjan(int u) { dfn[u] = low[u] = ++ptot, inst[u] = true, stk[++tail] = u; for (int i = phead[u]; i != -1; i = edges[i].nxt) if (dfn[edges[i].to] == 0) tarjan(edges[i].to), low[u] = min(low[u], low[edges[i].to]); else if (inst[edges[i].to]) low[u] = min(low[u], dfn[edges[i].to]); if (dfn[u] == low[u]) { ncnt++; do { aff[stk[tail]] = ncnt, sccs[ncnt].push_back(stk[tail]), inst[stk[tail]] = false, pos[stk[tail]] = sccs[ncnt].size(); } while (stk[tail--] != u); } } void output(int siz) { for (int i = 1; i <= siz; i++, puts("")) for (int j = 1; j <= siz + 1; j++) printf("%.3lf ", mat[i][j]); } void processSCC(int id) { int siz = sccs[id].size(); memset(mat, 0, sizeof(mat)); for (int idx = 1; idx <= siz; idx++) { int u = sccs[id][idx - 1]; for (int i = rhead[u]; i != -1; i = edges[i].nxt) if (aff[edges[i].to] == aff[u]) { mat[pos[edges[i].to]][pos[u]] += 1.0 / double(outdeg[edges[i].to]); mat[pos[edges[i].to]][siz + 1] -= 1.0 / double(outdeg[edges[i].to]); } } for (int idx = 1; idx <= siz; idx++) { int u = sccs[id][idx - 1]; mat[idx][siz + 1] -= f[u]; if (u == end_pt) memset(mat[idx], 0, sizeof(mat[idx])); mat[idx][idx] -= 1.0; } gauss(siz); for (auto x : sccs[id]) f[x] = mat[pos[x]][siz + 1]; } void dfs(int u) { vis[u] = true; if (u == end_pt) return; for (int i = phead[u]; i != -1; i = edges[i].nxt) { if (aff[edges[i].to] != aff[u]) indeg[aff[u]]++; if (!vis[edges[i].to]) dfs(edges[i].to); } } int main() { memset(rhead, -1, sizeof(rhead)), memset(phead, -1, sizeof(phead)); scanf("%d%d%d%d", &n, &m, &start_pt, &end_pt); for (int i = 1, u, v; i <= m; i++) scanf("%d%d", &u, &v), addpath(phead, u, v), addpath(rhead, v, u), outdeg[u]++; for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i); dfs(start_pt); for (int i = 1; i <= n; i++) if (vis[i] && aff[i] != aff[end_pt] && indeg[aff[i]] == 0) puts("INF"), exit(0); queue<int> q; q.push(aff[end_pt]); while (!q.empty()) { int u = q.front(); q.pop(); processSCC(u); if (u == aff[start_pt]) printf("%.3lf\n", fabs(f[start_pt])), exit(0); for (auto key : sccs[u]) for (int i = rhead[key]; i != -1; i = edges[i].nxt) if (aff[edges[i].to] != aff[key]) { f[edges[i].to] += (f[key] + 1.0) / double(outdeg[edges[i].to]); if (--indeg[aff[edges[i].to]] == 0) q.push(aff[edges[i].to]); } } puts("INF"); return 0; }
// BZ2707.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e4 + 200, MAX_M = 1001000;
const double eps = 1e-8;

int n, m, phead[MAX_N], rhead[MAX_N], current, start_pt, end_pt, aff[MAX_N], dfn[MAX_N], low[MAX_N], ptot, stk[MAX_N], tail;
int ncnt, outdeg[MAX_N], indeg[MAX_N], pos[MAX_N];
double mat[220][220], f[MAX_N];
bool vis[MAX_N], inst[MAX_N];
vector<int> sccs[MAX_N];

struct edge
{
    int to, nxt;
} edges[MAX_M * 3];

void addpath(int *header, int src, int dst)
{
    edges[current].to = dst, edges[current].nxt = header[src];
    header[src] = current++;
}

void gauss(int siz)
{
    for (int i = 1; i <= siz; i++)
    {
        int key = i;
        for (int j = i + 1; j <= siz; j++)
            if (fabs(mat[j][i]) > fabs(mat[key][i]))
                key = j;
        if (fabs(mat[key][i]) <= eps)
            continue;
        if (key != i)
            for (int j = 1; j <= siz + 1; j++)
                swap(mat[i][j], mat[key][j]);
        double tmp = mat[i][i];
        for (int j = i; j <= siz + 1; j++)
            mat[i][j] /= tmp;
        for (int j = 1; j <= siz; j++)
            if (i != j)
            {
                double rate = mat[j][i];
                for (int k = i; k <= siz + 1; k++)
                    mat[j][k] -= rate * mat[i][k];
            }
    }
}

void tarjan(int u)
{
    dfn[u] = low[u] = ++ptot, inst[u] = true, stk[++tail] = u;
    for (int i = phead[u]; i != -1; i = edges[i].nxt)
        if (dfn[edges[i].to] == 0)
            tarjan(edges[i].to), low[u] = min(low[u], low[edges[i].to]);
        else if (inst[edges[i].to])
            low[u] = min(low[u], dfn[edges[i].to]);
    if (dfn[u] == low[u])
    {
        ncnt++;
        do
        {
            aff[stk[tail]] = ncnt, sccs[ncnt].push_back(stk[tail]), inst[stk[tail]] = false, pos[stk[tail]] = sccs[ncnt].size();
        } while (stk[tail--] != u);
    }
}

void output(int siz)
{
    for (int i = 1; i <= siz; i++, puts(""))
        for (int j = 1; j <= siz + 1; j++)
            printf("%.3lf ", mat[i][j]);
}

void processSCC(int id)
{
    int siz = sccs[id].size();
    memset(mat, 0, sizeof(mat));
    for (int idx = 1; idx <= siz; idx++)
    {
        int u = sccs[id][idx - 1];
        for (int i = rhead[u]; i != -1; i = edges[i].nxt)
            if (aff[edges[i].to] == aff[u])
            {
                mat[pos[edges[i].to]][pos[u]] += 1.0 / double(outdeg[edges[i].to]);
                mat[pos[edges[i].to]][siz + 1] -= 1.0 / double(outdeg[edges[i].to]);
            }
    }
    for (int idx = 1; idx <= siz; idx++)
    {
        int u = sccs[id][idx - 1];
        mat[idx][siz + 1] -= f[u];
        if (u == end_pt)
            memset(mat[idx], 0, sizeof(mat[idx]));
        mat[idx][idx] -= 1.0;
    }
    gauss(siz);
    for (auto x : sccs[id])
        f[x] = mat[pos[x]][siz + 1];
}

void dfs(int u)
{
    vis[u] = true;
    if (u == end_pt)
        return;
    for (int i = phead[u]; i != -1; i = edges[i].nxt)
    {
        if (aff[edges[i].to] != aff[u])
            indeg[aff[u]]++;
        if (!vis[edges[i].to])
            dfs(edges[i].to);
    }
}

int main()
{
    memset(rhead, -1, sizeof(rhead)), memset(phead, -1, sizeof(phead));
    scanf("%d%d%d%d", &n, &m, &start_pt, &end_pt);
    for (int i = 1, u, v; i <= m; i++)
        scanf("%d%d", &u, &v), addpath(phead, u, v), addpath(rhead, v, u), outdeg[u]++;
    for (int i = 1; i <= n; i++)
        if (!dfn[i])
            tarjan(i);
    dfs(start_pt);
    for (int i = 1; i <= n; i++)
        if (vis[i] && aff[i] != aff[end_pt] && indeg[aff[i]] == 0)
            puts("INF"), exit(0);
    queue<int> q;
    q.push(aff[end_pt]);
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        processSCC(u);
        if (u == aff[start_pt])
            printf("%.3lf\n", fabs(f[start_pt])), exit(0);
        for (auto key : sccs[u])
            for (int i = rhead[key]; i != -1; i = edges[i].nxt)
                if (aff[edges[i].to] != aff[key])
                {
                    f[edges[i].to] += (f[key] + 1.0) / double(outdeg[edges[i].to]);
                    if (--indeg[aff[edges[i].to]] == 0)
                        q.push(aff[edges[i].to]);
                }
    }
    puts("INF");
    return 0;
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *