WA#62~66袜子求条
查看原帖
WA#62~66袜子求条
883803
Mason123456楼主2025/7/27 17:11

#62 - 63 答案比输出多 11

#64 - 66 答案比输出多 22

尝试 + rand()%3 最优情况只错 44 个点

qwq 求条

#include <bits/stdc++.h>
#define pb push_back
#define pii pair<int, int>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
using ll = long long;
const int N = 205, M = 5e4 + 5;
const ll inf = 2e18;
ll dis1[N], dis2[N], dis3[N], dis4[N], dis5[N], dis6[N];
int fa1[N], fa2[N], mrk1[M], mrk2[M];
int delnum, addu, addv, addw;
int p[M], w[M];
pii e[M];
vector<pii> g1[N], g2[N];
vector<int> num[N];
int n, m;

void dij(int s, vector<pii> *g, int zt) {
    vector<ll> dis(n + 5, inf);
    vector<int> vis(n + 5);
    dis[s] = 0;
    priority_queue<pair<ll, int>> q;
    q.push({0, s});
    while (!q.empty()) {
        ll d = -q.top().first;
        int u = q.top().second;
        q.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        // 添加反向边处理
        if (u == addu && d + addw < dis[addv]) {
            dis[addv] = d + addw;
            q.push({-dis[addv], addv});
        }
        int pos = 0;
        for (auto x : g[u]) {
            int v = x.first, w = x.second;
            // 修复:跳过删除边后仍需 pos++
            if (zt >= 5 && num[u][pos] == delnum) {
                pos++;
                continue;
            }
            if (dis[u] + w < dis[v]) {
                dis[v] = dis[u] + w;
                // 仅记录前驱节点
                if (zt == 1) fa1[v] = u;
                if (zt == 2) fa2[v] = u;
                q.push({-dis[v], v});
            }
            pos++;
        }
    }
    // 存储结果
    for (int i = 1; i <= n; i++) {
        if (zt == 1) dis1[i] = dis[i];
        if (zt == 2) dis2[i] = dis[i];
        if (zt == 3) dis3[i] = dis[i];
        if (zt == 4) dis4[i] = dis[i];
        if (zt == 5) dis5[i] = dis[i];
        if (zt == 6) dis6[i] = dis[i];
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
//    freopen("P6880_62.in", "r", stdin);
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int u, v;
        cin >> u >> v >> w[i] >> p[i];
        g1[u].pb({v, w[i]});
        num[u].pb(i);
        g2[v].pb({u, w[i]});
        e[i] = {u, v};
    }
    
    // 初始 Dijkstra
    dij(1, g1, 1);
    dij(n, g1, 2);
    dij(1, g2, 3);
    dij(n, g2, 4);

    // 回溯标记 1->n 路径
    if (dis1[n] < inf) {
        int uu = n;
        while (uu != 1) {
            int prev = fa1[uu];
            ll mxs = inf;
            // 找到连接 prev->uu 的边
            for (int i = 0; i < g1[prev].size(); i++) {
                if (g1[prev][i].first == uu && g1[prev][i].second < mxs) {
                    mrk1[num[prev][i]] = 1;
                    mxs = g1[prev][i].second;
                    break;
                }
            }
            uu = prev;
        }
    }

    // 回溯标记 n->1 路径
    if (dis2[1] < inf) {
        int uu = 1;
        while (uu != n) {
            int prev = fa2[uu];
            ll mxs = inf;
            for (int i = 0; i < g1[prev].size(); i++) {
                if (g1[prev][i].first == uu && g1[prev][i].second < mxs) {
                    mrk2[num[prev][i]] = 1;
                    mxs = g1[prev][i].second;
                    break;
                }
            }
            uu = prev;
        }
    }

    ll mincost = dis1[n] + dis2[1];
    for (int i = 1; i <= m; i++) {
        int u = e[i].first, v = e[i].second;
        if (mrk1[i] || mrk2[i]) {
            delnum = i;
            addu = v;
            addv = u;
            addw = w[i];
            // 关键修复:对修改后的图计算双路径
            dij(1, g1, 5);  // 1->n 在新图
            dij(n, g1, 6);  // n->1 在新图
            mincost = min(mincost, dis5[n] + dis6[1] + p[i]);
        } else {
            // 非最短路径边
            ll path1 = min(dis1[n], dis1[v] + dis4[u] + w[i]);
            ll path2 = min(dis2[1], dis2[v] + dis3[u] + w[i]);
            mincost = min(mincost, path1 + path2 + p[i]);
        }
    }
    cout << (mincost >= inf ? -1 : mincost) << '\n';
    return 0;
}
2025/7/27 17:11
加载中...