HDU1304(差分约束)

题意:
给你 n 个区间 [Ai, Bi],要求从每个区间中至少选出 Ci 个数出来组成一个序列
问:满足上面条件的序列的最短长度是多少?

解法:
对于 不等式 f(b)-f(a)>=c,建立 一条 b 到 a 的边 权值为 c,则求的最长路 即为 最小值(集合)
并且有隐含条件:0<=f(a)-f(a-1)<=1 则有边权关系(a,a-1,0)以及(a-1,a,-1);

一般地,差分约束系统分两类:求最大差和最小差

  1. 求最大差
    建立形如 A-B<=C 的不等式,在原图中添加边 (B, A) 边权为 C ,对建好的图跑最短路,如果存在负环,无解(判断条件为某点被更新了 n 次),n 为图中点的数量
  2. 求最小差
    建立形如 A-B>=C 的不等式,在原图中添加边 (B, A) 边权为 C ,对建好的图跑最长路,如果存在正环,无解(判断条件为某点被更新了 n 次),n 为图中点的数
//https://blog.csdn.net/lp_opai/article/details/46874659
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;

const int inf = 99999999;
const int maxn = 50000 + 10;
struct edge {
    int v, w;
};
vector<vector<edge>>a;
vector<int>dis(maxn, -inf);//最长路修改1
vector<bool>flag(maxn, false);

void add_edge(int u, int v, int w) {
    edge tmp;
    tmp.v = v;
    tmp.w = w;
    a[u].push_back(tmp);
}

void spfa(int s) {
    queue<int>q;
    q.push(s);
    dis[s] = 0; flag[s] = true;
    while (!q.empty()) {
        int u = q.front(); q.pop(); flag[u] = false;
        for (int i = 0; i < a[u].size(); i++) {
            if (dis[a[u][i].v] < dis[u] + a[u][i].w) {//最长路修改2
                dis[a[u][i].v] = dis[u] + a[u][i].w;
                if (!flag[a[u][i].v]) {
                    q.push(a[u][i].v);
                    flag[a[u][i].v] = true;
                }
            }
        }
    }
}

int main() {
    int n, m, aa = maxn, b = 0, c;
    scanf("%d%d", &n, &m);
    a.resize(maxn);
    for (int i = 0; i < m; i++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        if (aa > u) aa = u;
        if (b < v + 1) b = v + 1;
        add_edge(u, v + 1, w);
    }
    for (int i = aa; i <= b; i++) {
        add_edge(i, i - 1, -1);
        add_edge(i - 1, i, 0);
    }
    spfa(aa);
    printf("%d\n", dis[b]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值