关系运算图

探讨如何解决有向图中,通过给每个顶点分配一个整数值,使得图中每条边的关系运算符(‘<’, ‘>’, ‘=’)得到满足的问题。介绍了一种基于SPFA算法的解决方案,用于寻找满足条件的最小整数值k。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

描述 Description
给出一有向图,图中每条边都被标上了关系运算符‘<’,‘>’,‘=’。现在要给图中每个顶点标上一个大于等于0,小于等于k的某个整数使所有边上的符号得到满足。若存在这样的k,则求最小的k,若任何k都无法满足则输出NO。
例如下表中最小的k为2。
结点1>结点2
结点2>结点3
结点2>结点4
结点3=结点4
如果存在这样的k,输出最小的k值;否则输出‘NO’。
输入格式 Input Format
共二行,第一行有二个空格隔开的整数n和m。n表示G的结点个数,m表示G的边数,其中1<=n<=1000, 0<=m<=10000。全部结点用1到n标出,图中任何二点之间最多只有一条边,且不存在自环。
第二行共有3m个用空格隔开的整数,第3i-2和第3i-1(1<=i<=m)个数表示第i条边的顶点。第3i个数表示第i条边上的符号,其值用集合{-1,0,1}中的数表示:-1表示‘<’, 0 表示‘=’, 1表示‘>’。
输出格式 Output Format
仅一行,如无解则输出‘NO’;否则输出最小的k的值。
样例输入 Sample Input
4 4
1 2 -1 2 3 0 2 4 -1 3 4 -1
样例输出 Sample Output
2

题解

差分约束的题。
spfa跑最长路+判负环。

code

#include <algorithm>
#include <cctype>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <deque>
#include <functional>
#include <list>
#include <map>
#include <iomanip>
#include <iostream>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>

#define _ 0
#define fup(i, a, b) for (i = a; i <= b; ++i)
#define fdown(i, a, b) for (i = a; i >= b; --i)
typedef long long ull;
const int maxn = 1e6;
const int inf = 0x3f3f3f3f;

namespace millope {
    inline void swap(int a, int b) { a ^= b; b ^= a; a^= b; }
    inline int max(int a, int b) { return a > b ? a : b; }
    inline int min(int a, int b) { return a > b ? b : a; }
    inline int read() {
        int s = 0, w = 1;
        char ch = getchar();
        while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
        while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch - '0'); ch = getchar(); }
        return s * w;
    }
}
using namespace millope;

int n;
int m;
int tot;
int ans;
int cnt[maxn];
int link[maxn];
int dis[maxn];
bool vis[maxn];
struct Edge { int next, to, dis; } e[maxn];

inline void add(int from ,int to, int dis) {
    e[++tot].to = to;
    e[tot].dis = dis;
    e[tot].next = link[from];
    link[from] = tot;
}

void spfa(int k) {
    std::queue<int> q;
    memset(dis, 0xcf, sizeof(dis));
    memset(vis, false, sizeof(vis));
    dis[k] = 0, vis[k] = true;
    q.push(k); cnt[k]++;
    while (!q.empty()) {
        int u = q.front(); 
        q.pop(); vis[u] = false;
        for (int i = link[u]; i; i = e[i].next) {
            int v = e[i].to;
            if (dis[v] < dis[u] + e[i].dis) {
                dis[v] = dis[u] + e[i].dis;
                if (!vis[v]) {
                    vis[v] = true;
                    q.push(v);
                    cnt[v]++;
                    // printf("%d===\n", cnt[v]);
                    if (cnt[v] > n) {
                        printf("NO\n");
                        exit(0);
                    }
                }
            }  
        }
    }
}

int main() {
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    n = read(), m = read(); ans = -inf;
    for (int i = 1, a, b, c; i <= m; ++i) {
        a = read(), b = read(), c= read();
        if (c == -1) add(b, a, 1);
        else if (c == 0) add(a, b, 0), add(b, a, 0);
        else if (c == 1) add(a, b, 1);
    }
    for (int i = 1; i <= n; ++i) {
        add(0, i, 0);
    }
    spfa(0);
    for (int i = 1; i <= n; ++i) {
        ans = max(ans, dis[i]);
    }
    printf("%d\n", ans);
    return (0^_^0);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值