POJ - 1201(差分约束入门)

本文介绍了如何解决POJ 1201问题,这是一个差分约束入门题目。通过建立模型并转换为最长路问题,利用最短路算法求解x[i]之间的约束,确保x[最大]-x[最小-1]的最小值。此外,还讨论了隐含的条件0<=x[i]-x[i-1]<=1,并提供了优化方法。

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

返回专题https://blog.youkuaiyun.com/wyxxzsy/article/details/82776590

废话不说,直接建模套板子
x[i] 代表 0~i 里点的个数
对于若干个x[i],有若干个约束条件
如样例:
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

第一个约束条件“3 7 3”
就是x[7]-x[2]>=3
最终要求 x[最大]-x[最小-1]的最小值
转换成最长路

模型2优化.给定一串序列 a 1 − a n a_1 - a_n a1an 并给出若干限制条件 a i − a j &gt; = c a_i - a_j&gt;=c aiaj>=c,要求 a k 1 a_{k1} ak1 a k 2 a_{k2} ak2 的最小可能差值?
方法:对于每个限制条件 a i − a j &gt; = c ⟹ a j − a i &lt; = − c a_i - a_j&gt;=c\Longrightarrow a_j - a_i&lt;=-c aiaj>=cajai<=c,从点i到点j建立一条边(-c),求 a k 1 a_{k1} ak1 a k 2 a_{k2} ak2 的最短路即可。

https://blog.youkuaiyun.com/wyxxzsy/article/details/82776590

除了明说的限制,还有隐含的条件
0 &lt; = a i − a i − 1 &lt; = 1 0&lt;= a_i-a_{i-1}&lt;=1 0<=aiai1<=1
从i~(i-1)加-c的边 就ok了
(被什么超级源点搞了半天,狗屎)

#include<iostream>
#include<stdio.h>
#include<string>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
#include<queue>
using namespace std;
#define clr(a, x) memset(a, x, sizeof(a))
#define mp(x, y) make_pair(x, y)
#define pb(x) push_back(x)
#define X first
#define Y second
#define fastin                    \
    ios_base::sync_with_stdio(0); \
    cin.tie(0);
typedef long long LL;
typedef pair<int, int> PII;
typedef vector<int> VI;
const int INF=0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-6;


const int N=50010;
const int M=500010;
int n,m;


int dis[N];
struct edge{
    int to;int v;
};
vector<edge> G[N];
int vis[N];
int cnt[N];//每个点的入队次数
void init(){
    for(int i=0;i<=N;i++) G[i].clear();
}
void addedge(int u,int v,int w){
    G[u].push_back(edge{v,w});
}
int spfa(int start){
    clr(vis,0);
    clr(dis,INF);
    queue<int> q;
    dis[start] = 0;
    //vis[start] = 1;
    clr(cnt,0);
    cnt[start] = 1;
    q.push(start);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0; //不在队列里了
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i].to;
            int cost=G[u][i].v;
            if(dis[v]>dis[u]+cost)
            {
                dis[v]=dis[u]+cost;
                if(!vis[v]){
                    vis[v] = 1;
                    q.push(v);
                    if(++cnt[v]>n) return 0;
                }
            }
        }
    }
    return 1;
}


int main()
{
    scanf("%d",&m);
    int s=INF,e=0;
    init();
    while(m--){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        a++,b++;
        s=min(a,s);
        e=max(e,b);
        addedge(a-1,b,-c);
    }
    for(int i=s;i<=e;i++){
        addedge(i-1,i,0);
        addedge(i,i-1,1);
    }
    n = e-s+10;
    spfa(s-1);
    printf("%d\n",-dis[e]);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值