首页 > 其他分享 >差分约束学习笔记

差分约束学习笔记

时间:2024-12-17 23:02:04浏览次数:7  
标签:ch int 短路 笔记 约束 vis edge 差分 dis

给定 \(n\) 个形如 \(a-b≤c\) 的式子,求一组解或求两个变量间的最值

转化为图论问题跑最短/长路即可。

例:P3275 [SCOI2011]糖果

简化题意:给定一串约束条件,求所有元素的最小值。

稍微转换一下,就是使两个元素差值尽可能小。

例如 \(x_1+c≤x_2\) 如果用最短路去约束,则会取到最小值,所以应该用最长路去维护。

具体原因我也解释不来屮。

又因为题意对每个元素都有大于等于1的约束,所以从超级源点向每个元素的边边权要设为1。

这题就做完了,但是有些些小细节。

#include<bits/stdc++.h>
#define N 200005
#define int long long
using namespace std;
 
inline int read(){
    int x=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w*x;
}

int n,k,cnt,ans;
int dis[N],head[N],tot[N];
bool vis[N];
struct node{int to,next,w;}edge[N<<1];

void add(int u,int v,int w){
    edge[++cnt]=(node){v,head[u],w};
    head[u]=cnt;
}
void spfa(){
    stack<int> q;
    q.push(0);
    vis[0]=1;
    while(!q.empty()){
        int u=q.top();q.pop();vis[u]=0;
        for(int i=head[u];i;i=edge[i].next){
            int v=edge[i].to;
            if(dis[u]+edge[i].w>dis[v]){
                dis[v]=dis[u]+edge[i].w;
                if(!vis[v]){
                    vis[v]=1;tot[v]++;
                    if(tot[v]>=n) {puts("-1");exit(0);}
                    q.push(v);
                }
            }
        }
    }
}
signed main(){
    n=read();k=read();
    for(int i=1;i<=k;++i){
        int x=read(),a=read(),b=read();
        if(x==1) add(a,b,0),add(b,a,0);
        else if(x==2) {
            if(a==b){puts("-1");return 0;}
            add(a,b,1);
        }
        else if(x==3) add(b,a,0);
        else if(x==4) {
            if(a==b){ puts("-1");return 0;}
            add(b,a,1);
        }
        else  add(a,b,0);
    }
    for(int i=1;i<=n;++i) add(0,i,1);
    spfa();
    for(int i=1;i<=n;++i)
        ans+=dis[i];
    printf("%lld",ans);
    return 0;
}

最小值同理。

我真不知道啥时跑最长啥时跑最短屮。

考场上随机应变

​ ——————water_tomato

upd. on 2022.7.15

好像又懂了,补充一下。

最大值

将约束条件转化为形如 \(dis_i\le dis_j+w\) 。

从 \(j\) 向 \(i\) 连一条边权为 \(w\) 的边,跑最短路。

为什么要跑最短路呢,因为跑最短路在这种情况下是跑到上界的,\(dis_i\) 就是把上界跑满的结果。

这样建图跑最长路就寄了,答案是错误的。

最小值

将约束条件转化为形如 \(dis_i\ge dis_j+w\) 。

从 \(j\) 向 \(i\) 连一条边权为 \(w\) 的边,跑最长路,也可以跑到上界。

我们令 \(dis_1=0\) ,则跑最长路跑出来的 \(dis_3=4\) ,刚好卡到上界。

跑最短路跑出来的 \(dis_3=2\) ,不满足 1 , 4 之间的关系。

上面的最大值同理。

参考资料

https://blog.csdn.net/thexue/article/details/123587112

标签:ch,int,短路,笔记,约束,vis,edge,差分,dis
From: https://www.cnblogs.com/lxgswrz/p/18613589

相关文章

  • 模拟退火学习笔记
    模拟退火,RP检测器,玄学算法,yyds。看什么学习笔记,当然是看日报了。过程就是模拟冶金学的退火过程,乱搞,具体理论的证明我也不是很懂。流程图(自己懂就好):优化/乱搞温度T的初始值设置问题。温度T的初始值设置是影响模拟退火算法全局搜索性能的重要因素之一、初始温度高,则搜索......
  • 点分治学习笔记
    定义点分治,顾名思义,就是通过基于点的分治的一种算法。通常用于处理树上问题,如树上所有路径统计。我们设一次操作的时间复杂度为\(O(1)\),那么一次点分治复杂度为\(O(n\logn)\)。具体流程操作->分治->操作……(不知道怎么讲)点分治的核心主要在于高效的分治,每一次都可以将......
  • FHQ- Treap学习笔记
    FHQ-Treap与Treap都保证在第一关键字有序的情况下,维护第二关键字以达到平衡的目的。但是Treap用的是旋转,FHQ-Treap用的是分裂和合并。FHQ-Treap与Treap不同的地方:优美的分裂和合并。非旋。支持区间修改FHQ-Treap与Treap相同的地方:都保证在第一关键字有序的情况......
  • 树状数组学习笔记
    位运算是补码进行运算的因此可以解释负数进行位运算时的奇妙现象补码:正数的补码就是其本身负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后+1.(即在反码的基础上+1)E:原码:10000001;补码:01111111.lowbit:lowbit这个函数的功能就是求某一个数的二进制表示......
  • 主席树学习笔记
    权值线段树就是指线段树的叶子节点保存的是当前值的个数。权值线段树一般支持以下三个操作:inserterase/removequery贴一个alphadalao的题解。主席树主席树,也叫做可持久化线段树,准确来说,应该叫做可持久化权值线段树,因为其中的每一颗树都是一颗权值线段树。经典例......
  • zkw线段树学习笔记
    先%一下zkw。stozkworzzkw线段树是一个改良版的线段树。其功能与传统线段树相同,也是用于维护区间信息。但是zkw线段树有很多优点:代码简短;纯天然非递归;常数小(尤其在差分区间更新时)特点:堆式储存,找父亲只需右移一位。建树和线段树一样,父节点左移一位为左儿子,再+1(或者|......
  • 奇绩创坛公开课第01课_创业走出第一步_陆奇:学习笔记
    写在前面背景:笔者已完整完成奇绩创坛官网上面的创业公开课,并且取得了结课证书。并且在2024年12月份参加了奇绩在我们学校的线下公开课。由于发现这些创业课程的质量很好,于是决定将学习笔记发布出来。一方面,对于学校里面的学生来说,这些经过萃取过的创业知识和方法论很有指......
  • Golang学习笔记_12——结构体
    Golang学习笔记_09——if条件判断Golang学习笔记_10——SwitchGolang学习笔记_11——指针文章目录结构体1.定义2.访问&&修改3.零值初始化&使用指针初始化4.匿名字段和嵌套结构体5.结构体方法和接收者源码结构体Go语言中的结构体(struct)是一种复合数据......
  • 代理 mitmproxy Python启动时,配置 block_global 参数,使用笔记(三)
    代理mitmproxyPython启动时,配置block_global参数,使用笔记(三)为什么要加block_global=false?,若不加,则只能本地拦截,而移动设备,或非本机请求时则无法被拦截将报错如下:Clientconnectionfrom192.167.6.166killedbyblock_globaloption注意:使用Python的非命令行启动,之前的......
  • 阅读笔记
    技术深度与广度在《程序员修炼之道》中,作者强调了程序员在技术深度和广度上的均衡发展。技术深度意味着对某一领域技术的深入理解和熟练掌握;而技术广度则要求程序员了解多个技术领域,以便在解决问题时能够灵活应用。深入掌握核心技能:书中提到,程序员应该深入掌握至少一种编程语言......