StkOvflow

STACK OVERFLOW!

一言(ヒトコト)

Who laughs last laughs best!
——Emma

洛谷P2294. [HNOI2005] 狡猾的商人

题意简述

给定 n 个数字a1an,给定 m 组约束关系,其中有三个整数 s,t,v 表示从第 s 个月到第 t 个月的收入为 v, 最后判断 a 数列与约束关系有没有冲突。

解题思路

从前缀和思想我们可以发现,对于约束关系{s,t,v}我们可以转化成这样:

x[i] 表示前 i 天的收入之和,所以 [s,t]这段时间的收入 v 可以表示成下面这样:

xtxs1=v

然后用差分约束系统常用的技巧等于号变成两个不等号可以得到下式

xtxs1+vs1t,w=v

xs1xtvts1,w=v

最后用最短路判断负环即可,有负环代表账单造假输出false,否则输出true

代码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 110, M = 2020;
int h[N], a[N], n, m, idx;
int dist[N], st[N], ring;

struct Edge 
{
    int cur, ne, w;
} e[M];

void add(int a, int b, int c) 
{
    e[ ++ idx].cur = b, e[idx].ne = h[a];
    e[idx].w = c, h[a] = idx;
}

void dfs(int u) 
{
    st[u] = 1;

    for (int i = h[u]; i; i = e[i].ne) 
    {
        int j = e[i].cur;
        if (dist[j] > dist[u] + e[i].w) 
        {
            dist[j] = dist[u] + e[i].w;
            if (st[j] == 1) 
            {
                ring = true ;
                break ;
            }
            dfs(j);
            if (ring) return ;
        }
    }

    st[u] = 2;
}

int main() 
{
    int T;
    scanf("%d", &T);

    while (T -- ) 
    {
        scanf("%d%d", &n, &m);

        memset(h, 0, sizeof h);
        memset(st, 0, sizeof st);
        idx = ring = 0;

        while (m -- ) 
        {
            int s, t, v;
            scanf("%d%d%d", &s, &t, &v);
            add(s - 1, t, v), add(t, s - 1, -v);
        }

        for (int i = 1; i <= n; i ++ ) 
        {
            if (ring) break ;
            if (st[i]) continue ;
            dfs(i);
        }

        puts(ring ? "false" : "true");
    }
}

--------------------------分割线-----------------------

值得一提的是这道题也可以用带权并查集来解,定义 d[x]x 到所在集合根节点的距离,两点之间的距离应该就是 d[x]d[y],合并的时候记得吧父节点的累加到儿子身上。

并查集代码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 220;
int d[N], p[N], n, m, T, ok;

int find(int x) 
{
    if (x == p[x]) return x;
    int root = find(p[x]);
    d[x] += d[p[x]];
    return p[x] = root;
}

void add(int u, int v, int w) 
{
    int fu = find(u), fv = find(v);

    if (fu != fv) 
    {
        p[fv] = fu;
        d[fv] = d[u] - d[v] + w;
    }
    else if (d[v] - d[u] != w) ok = 0;
}

int main() 
{
    scanf("%d", &T);

    while (T -- ) 
    {
        scanf("%d%d", &n, &m);

        for (int i = 0; i <= n; i ++ ) d[i] = 0, p[i] = i;

        ok = 1;
        while (m -- ) 
        {
            int s, t, v;
            scanf("%d%d%d", &s, &t, &v);
            add(s - 1, t, v);
        }

        puts(ok ? "true" : "false");
    }

    return 0;
}

区间DP

容易得到以下状态表示f[l][r][l,r]
枚举这段时间的所有断点k[l,r1],可以把[l,r]区间切割成两部分[l,k],[k+1,r]
然后f[l][r]=f[l][k]+f[k+1][r],我们用INF表示区间营业额没有确定,如果区间营业额已经确定且与两个子区间的和不同,代表冲突,可以输出false

代码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 220, INF = 0x3f3f3f3f;
int f[N][N], n, m, T, ok;

int main() 
{
    scanf("%d", &T);

    while (T -- ) 
    {
        scanf("%d%d", &n, &m);
        ok = 1;
        
        memset(f, 0x3f, sizeof f);
        while (m -- ) 
        {
            int s, t, v;
            scanf("%d%d%d", &s, &t, &v);
            if (f[s][t] == INF) f[s][t] = v;
            else if (f[s][t] != v) ok = 0;
        }

        if (!ok) 
        {
            puts("false");
            continue ;
        }

        for (int len = 1; len <= n && ok; len ++ ) 
        {
            for (int l = 1, r = l + len - 1; r <= n; l ++, r ++ ) 
            {
                for (int k = l; k < r; k ++ ) 
                {
                    if (f[l][k] != INF && f[k + 1][r] != INF)
                    {
                        if (f[l][r] == INF) f[l][r] = f[l][k] + f[k + 1][r];
                        else if (f[l][r] != f[l][k] + f[k +1][r]) ok = 0;
                    }
                }
            }
        }

        puts(ok ? "true" : "false");
    }
    
    return 0;
}
posted @   StkOvflow  阅读(110)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
点击右上角即可分享
微信分享提示