[USACO18DEC]Fine Dining

本文探讨了使用SPFA算法解决一个有趣的问题:如何确定每头牛是否能通过选择一条包含草堆的最短路径来降低其行走成本。通过构建分层图并在有草垛的点上引入负权边,最终比较两个维度上的距离,从而判断目标是否能够达成。
摘要由CSDN通过智能技术生成

题面

\(Solution:\)

一开始想的是先跑一遍最短路,然后拆点之后再跑一遍,比较两次dis,然后发现拆点后会有负环(可能是我没想对拆点的方法),于是就放弃了拆点法。

我们考虑强制让每头牛选择走一条最短的,有草堆的路径,然后比较单纯的最短路。

然后就想到了分层图,在每一个有草垛的点向第二维图对应的点连一条单向的,权值为-美味值的边,这样第二维图上的dis就是每头牛选择走一条最短,有草堆的路径长度,再和第一维比较即可.注意有负边,跑某死亡算法.

\(Source\)

#include <set>
#include <queue>
#include <cmath>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <assert.h>
#include <algorithm>

using namespace std;

#define fir first
#define sec second
#define pb push_back
#define mp make_pair
#define LL long long
#define INF (0x3f3f3f3f)
#define mem(a, b) memset(a, b, sizeof (a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define Debug(x) cout << #x << " = " << x << endl
#define travle(i, x) for (register int i = head[x]; i; i = nxt[i])
#define For(i, a, b) for (register int (i) = (a); (i) <= (b); ++ (i))
#define Forr(i, a, b) for (register int (i) = (a); (i) >= (b); -- (i))
#define file(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
#define ____ debug("go\n")

namespace io {
    static char buf[1<<21], *pos = buf, *end = buf;
    inline char getc()
    { return pos == end && (end = (pos = buf) + fread(buf, 1, 1<<21, stdin), pos == end) ? EOF : *pos ++; }
    inline int rint() {
        register int x = 0, f = 1;register char c;
        while (!isdigit(c = getc())) if (c == '-') f = -1;
        while (x = (x << 1) + (x << 3) + (c ^ 48), isdigit(c = getc()));
        return x * f;
    }
    inline LL rLL() {
        register LL x = 0, f = 1; register char c;
        while (!isdigit(c = getc())) if (c == '-') f = -1;
        while (x = (x << 1ll) + (x << 3ll) + (c ^ 48), isdigit(c = getc()));
        return x * f;
    }
    inline void rstr(char *str) {
        while (isspace(*str = getc()));
        while (!isspace(*++str = getc()))
            if (*str == EOF) break;
        *str = '\0';
    }
    template<typename T> 
        inline bool chkmin(T &x, T y) { return x > y ? (x = y, 1) : 0; }
    template<typename T>
        inline bool chkmax(T &x, T y) { return x < y ? (x = y, 1) : 0; }    
}
using namespace io;

const int N = 5e4 + 2, M = 1e5 + 2;

int n, m, k;
int dis[N<<1];

namespace Gragh {
    int head[N<<1], ver[(M<<2) + N], nxt[(M<<2) + N], tot, edge[(M<<2) + N];
    inline void add(int u, int v, int w) {
        ver[++tot] = v, edge[tot] = w, nxt[tot] = head[u], head[u] = tot;
    }
} using namespace Gragh;

bool vis[N<<1];

void SPFA(int st) {
    queue<int> q;
    memset(dis, 0x3f, sizeof dis);
    q.push(st);
    dis[st] = 0;
    vis[st] = 1;
    while (q.size()) {
        int u = q.front(); q.pop(); vis[u] = 0;
        for (register int i = head[u]; i; i = nxt[i]) {
            if (dis[ver[i]] > dis[u] + edge[i]) {
                dis[ver[i]] = dis[u] + edge[i];
                if (!vis[ver[i]]) {
                    vis[ver[i]] = 1;
                    q.push(ver[i]);
                }
            }   
        }
    }
}

int main() {
#ifndef ONLINE_JUDGE
    file("Fine_Dining");
#endif
    n = rint(), m = rint(), k = rint();
    For (i, 1, m) {
        int u = rint(), v = rint(), w = rint();
        add(u, v, w); add(v, u, w);
        add(u + n, v + n, w); add(v + n, u + n, w);
    }
    For (i, 1, k) {
        int u = rint(), val = rint();
        add(u, u + n, -val);
    }
    SPFA(n);
    for (register int i = 1; i < n; ++ i) if (dis[i] >= dis[i + n]) {
        puts("1");
    } else puts("0");
}

转载于:https://www.cnblogs.com/cnyali-Tea/p/10478942.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值