Loading [MathJax]/extensions/tex2jax.js

P3547:「POI2013」CEN-Price List – 题解

主要思路

考虑三种最短路的形式:\(A \times dist, \lfloor \frac{dist}{2} \rfloor B + (dist \bmod 2) A, kB \)。前两种直接 BFS 一遍即可,第三种对路径有特殊要求:不能存在边集外一条边可以使得与路径的某两条边形成三元环。

说到三元环,我们就可以仿照那个根号的方法,先做标记,然后再枚举中间边。然而,这里我们没法拆成单向边,所以直接根号的做法是假的。

继续思考一个三元环 \((u, v, w)\),发现如果我们找到了一个这样的三元环,至少我们可以直接删掉 \((v, w)\),因为这个边不会再发挥作用了(因为我们在 BFS 的时候肯定提供最优解)。

代码

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// P3547.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e5 + 200, INF = 0x3f3f3f3f;
int n, m, K, A, B, phead[MAX_N], rhead[MAX_N], current, dist[MAX_N];
int ans[MAX_N];
bool tag[MAX_N];
struct edge
{
int to, nxt, pre;
} edges[MAX_N << 2];
void addpath(int *head, int src, int dst)
{
edges[current].to = dst, edges[current].nxt = head[src], edges[current].pre = -1;
if (edges[current].nxt != -1)
edges[edges[current].nxt].pre = current;
head[src] = current++;
}
void remove(int *head, int u, int eid)
{
if (edges[eid].pre != -1)
edges[edges[eid].pre].nxt = edges[eid].nxt;
if (edges[eid].nxt != -1)
edges[edges[eid].nxt].pre = edges[eid].pre;
if (head[u] == eid)
head[u] = edges[eid].nxt;
}
int main()
{
memset(phead, -1, sizeof(phead)), memset(rhead, -1, sizeof(rhead));
scanf("%d%d%d%d%d", &n, &m, &K, &A, &B);
for (int i = 1, u, v; i <= m; i++)
{
scanf("%d%d", &u, &v);
addpath(phead, u, v), addpath(phead, v, u);
addpath(rhead, u, v), addpath(rhead, v, u);
}
memset(dist, -1, sizeof(dist)), memset(ans, 0x3f, sizeof(ans));
queue<int> q;
q.push(K), dist[K] = 0;
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = phead[u]; i != -1; i = edges[i].nxt)
if (dist[edges[i].to] == -1)
dist[edges[i].to] = dist[u] + 1, q.push(edges[i].to);
}
for (int i = 1; i <= n; i++)
{
if (dist[i] == -1)
ans[i] = INF;
else
ans[i] = min(dist[i] * A, (dist[i] >> 1) * B + (dist[i] & 1) * A);
dist[i] = -1;
}
q.push(K), dist[K] = 0;
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = phead[u]; i != -1; i = edges[i].nxt)
tag[edges[i].to] = true;
for (int i = phead[u]; i != -1; i = edges[i].nxt)
for (int j = rhead[edges[i].to]; j != -1; j = edges[j].nxt)
if (dist[edges[j].to] == -1 && tag[edges[j].to] == false)
{
dist[edges[j].to] = dist[u] + 1, remove(rhead, edges[i].to, j);
q.push(edges[j].to);
}
for (int i = phead[u]; i != -1; i = edges[i].nxt)
tag[edges[i].to] = false;
}
for (int i = 1; i <= n; i++)
{
if (dist[i] != -1)
ans[i] = min(ans[i], dist[i] * B);
dist[i] = -1;
}
for (int i = 1; i <= n; i++)
printf("%d\n", ans[i]);
return 0;
}
// P3547.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1e5 + 200, INF = 0x3f3f3f3f; int n, m, K, A, B, phead[MAX_N], rhead[MAX_N], current, dist[MAX_N]; int ans[MAX_N]; bool tag[MAX_N]; struct edge { int to, nxt, pre; } edges[MAX_N << 2]; void addpath(int *head, int src, int dst) { edges[current].to = dst, edges[current].nxt = head[src], edges[current].pre = -1; if (edges[current].nxt != -1) edges[edges[current].nxt].pre = current; head[src] = current++; } void remove(int *head, int u, int eid) { if (edges[eid].pre != -1) edges[edges[eid].pre].nxt = edges[eid].nxt; if (edges[eid].nxt != -1) edges[edges[eid].nxt].pre = edges[eid].pre; if (head[u] == eid) head[u] = edges[eid].nxt; } int main() { memset(phead, -1, sizeof(phead)), memset(rhead, -1, sizeof(rhead)); scanf("%d%d%d%d%d", &n, &m, &K, &A, &B); for (int i = 1, u, v; i <= m; i++) { scanf("%d%d", &u, &v); addpath(phead, u, v), addpath(phead, v, u); addpath(rhead, u, v), addpath(rhead, v, u); } memset(dist, -1, sizeof(dist)), memset(ans, 0x3f, sizeof(ans)); queue<int> q; q.push(K), dist[K] = 0; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = phead[u]; i != -1; i = edges[i].nxt) if (dist[edges[i].to] == -1) dist[edges[i].to] = dist[u] + 1, q.push(edges[i].to); } for (int i = 1; i <= n; i++) { if (dist[i] == -1) ans[i] = INF; else ans[i] = min(dist[i] * A, (dist[i] >> 1) * B + (dist[i] & 1) * A); dist[i] = -1; } q.push(K), dist[K] = 0; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = phead[u]; i != -1; i = edges[i].nxt) tag[edges[i].to] = true; for (int i = phead[u]; i != -1; i = edges[i].nxt) for (int j = rhead[edges[i].to]; j != -1; j = edges[j].nxt) if (dist[edges[j].to] == -1 && tag[edges[j].to] == false) { dist[edges[j].to] = dist[u] + 1, remove(rhead, edges[i].to, j); q.push(edges[j].to); } for (int i = phead[u]; i != -1; i = edges[i].nxt) tag[edges[i].to] = false; } for (int i = 1; i <= n; i++) { if (dist[i] != -1) ans[i] = min(ans[i], dist[i] * B); dist[i] = -1; } for (int i = 1; i <= n; i++) printf("%d\n", ans[i]); return 0; }
// P3547.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 200, INF = 0x3f3f3f3f;

int n, m, K, A, B, phead[MAX_N], rhead[MAX_N], current, dist[MAX_N];
int ans[MAX_N];
bool tag[MAX_N];

struct edge
{
    int to, nxt, pre;
} edges[MAX_N << 2];

void addpath(int *head, int src, int dst)
{
    edges[current].to = dst, edges[current].nxt = head[src], edges[current].pre = -1;
    if (edges[current].nxt != -1)
        edges[edges[current].nxt].pre = current;
    head[src] = current++;
}

void remove(int *head, int u, int eid)
{
    if (edges[eid].pre != -1)
        edges[edges[eid].pre].nxt = edges[eid].nxt;
    if (edges[eid].nxt != -1)
        edges[edges[eid].nxt].pre = edges[eid].pre;
    if (head[u] == eid)
        head[u] = edges[eid].nxt;
}

int main()
{
    memset(phead, -1, sizeof(phead)), memset(rhead, -1, sizeof(rhead));
    scanf("%d%d%d%d%d", &n, &m, &K, &A, &B);
    for (int i = 1, u, v; i <= m; i++)
    {
        scanf("%d%d", &u, &v);
        addpath(phead, u, v), addpath(phead, v, u);
        addpath(rhead, u, v), addpath(rhead, v, u);
    }
    memset(dist, -1, sizeof(dist)), memset(ans, 0x3f, sizeof(ans));
    queue<int> q;
    q.push(K), dist[K] = 0;
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (int i = phead[u]; i != -1; i = edges[i].nxt)
            if (dist[edges[i].to] == -1)
                dist[edges[i].to] = dist[u] + 1, q.push(edges[i].to);
    }
    for (int i = 1; i <= n; i++)
    {
        if (dist[i] == -1)
            ans[i] = INF;
        else
            ans[i] = min(dist[i] * A, (dist[i] >> 1) * B + (dist[i] & 1) * A);
        dist[i] = -1;
    }
    q.push(K), dist[K] = 0;
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (int i = phead[u]; i != -1; i = edges[i].nxt)
            tag[edges[i].to] = true;
        for (int i = phead[u]; i != -1; i = edges[i].nxt)
            for (int j = rhead[edges[i].to]; j != -1; j = edges[j].nxt)
                if (dist[edges[j].to] == -1 && tag[edges[j].to] == false)
                {
                    dist[edges[j].to] = dist[u] + 1, remove(rhead, edges[i].to, j);
                    q.push(edges[j].to);
                }
        for (int i = phead[u]; i != -1; i = edges[i].nxt)
            tag[edges[i].to] = false;
    }
    for (int i = 1; i <= n; i++)
    {
        if (dist[i] != -1)
            ans[i] = min(ans[i], dist[i] * B);
        dist[i] = -1;
    }
    for (int i = 1; i <= n; i++)
        printf("%d\n", ans[i]);
    return 0;
}

Leave a Reply

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