[差分约束] P3275 [SCOI2011] 糖果 & P1993 小K的农场 (洛谷) & poj 3169 Layout

差分约束系统有两种方式可以求解,最短路和最长路。当我们把不等式整理成d[a]+w<=d[b]时,我们求最长路。整理成d[a]+w>=d[b]时,我们求最短路。

最长路 找最小值 <= 数据最低的极限
最短路 找最大值 >= 数据最大的极限
这个是极限是存在得 不能<=-inf 大于 +inf 什么得
注意全部建图方向 都根据题 选取一个符号来决定

ps 对于某些不连通的图 建个0点 联通什么的

https://www.luogu.org/problemnew/show/P1993
P1993 小K的农场
差分约束 跑最短路 看负环就好 <= 不能最大得极限不是 —INF
要有
1:表示农场 a 比农场 b 至少多种植了 c 个单位的作物。即a>=b+c
2:表示农场 a 比农场 b 至多多种植了 c 个单位的作物。即a<=b+c
3:表示农场 a 与农场 b 种植数一样 即a=b 可以表示为 a - b == 0 和 b - a = = 0
以下 有找最短路 最长路 dis数组三角不等式 决定 c(u,v) 便是方向和权值
对于 1 来说
disa>=disb + c(a,b) 所以建边 a->b c的路
大于小于分清 按不等式走
这题也可以跑最长路 这个时候对于 1来说
disb<= disb-c(b,a) 所以建立 b->a -c 的路

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
#define ll long long 
const int INF=0x3f3f3f3f;
const int maxn = 1e4+5;
bool vis[maxn];
int dis[maxn]; 

int to[maxn<<2],val[maxn<<2],head[maxn],nxt[maxn<<2];
int cnt;

void add_edge(int a,int b,int v){
    to[++cnt]=b;
    nxt[cnt]=head[a];
    head[a]=cnt;
    val[cnt]=v;
}

bool spfa(int u){
    vis[u]=1;
    for(int i=head[u];i;i=nxt[i])
        if(dis[to[i]]>dis[u]+val[i]){
            dis[to[i]]=dis[u]+val[i];
            if(vis[to[i]])return 0;
            if(!spfa(to[i]))return 0;
        }
    vis[u]=0;
    return 1;
}

int main(){
    int n,m;
    int v,cmd;
    int a,b;
    cin>>n>>m;	
    for(int i=1;i<=n;i++) dis[i]=INF;
    for(int i=0;i<m;i++){
        cin>>cmd;
        switch(cmd){
            case 1:
                cin>>a>>b>>v;
                add_edge(b,a,v);
                break;
            case 2:
                cin>>a>>b>>v;
                add_edge(a,b,-v);
                break;
            case 3:
                cin>>a>>b;
                add_edge(a,b,0);
                add_edge(b,a,0);
                break;
        }
    }
    for(int i=1;i<=n;i++) add_edge(0,i,0);
    dis[0]=0;
    if(spfa(0)) cout<<"Yes\n";
    else cout<<"No\n";
    return 0;
} 

P3275 [SCOI2011]糖果
https://www.luogu.org/problemnew/show/P3275
既然是早最少要多少 就跑最长路 看最小值 答案是每个人到0的距离和
差分约束 跑最长路 看正环就好 >= 不能最底得极限不存在 是+INF

后面那个题 记得开LL 然后 倒这建0到(1,n) 的线 卡SPFAorz
这图建立就容易了 有了上一题

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
#define ll long long 
const int INF=0x3f3f3f3f3f3f3f3f;
const int maxn = 1e5+5;
bool vis[maxn];
ll dis[maxn]; 

int to[maxn<<2],val[maxn<<2],head[maxn],nxt[maxn<<2];
int cnt;

void ade(int a,int b,int v){
    to[++cnt]=b;
    nxt[cnt]=head[a];
    head[a]=cnt;
    val[cnt]=v;
}

bool spfa(int u){
    vis[u]=1;
    for(int i=head[u];i;i=nxt[i])
        if(dis[to[i]]<dis[u]+val[i]){
            dis[to[i]]=dis[u]+val[i];
            if(vis[to[i]])return 0;
            if(!spfa(to[i]))return 0;
        }
    vis[u]=0;
    return 1;
}

int main(){
    int n,m;
    int v,cmd;
    int a,b;
    cin>>n>>m;
    for(int i=0;i<m;i++){
        cin>>cmd>>a>>b;
        if(cmd==1) ade(a,b,0),ade(b,a,0);
        if(cmd==2) ade(a,b,1);
        if(cmd==3) ade(b,a,0);
        if(cmd==4) ade(b,a,1);
        if(cmd==5) ade(a,b,0);
    } 
    for(int i=n;i>=1;i--) ade(0,i,1),dis[i]=-INF;
    dis[0]=0;
    if(!spfa(0)){
        cout<<-1<<endl;
    }else{
        ll ans=0;
        for(int i=1;i<=n;i++) ans+=dis[i];
        cout<<ans<<endl;
    }
        
    return 0;
} 

Layout
http://poj.org/problem?id=3169
数据保证 大的在小的 左边
找 1和n最远距离 跑最短路 数据最大值是上线

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
#define ll long long 
const int INF=0x3f3f3f3f;
const int maxn = 1e4+5;
bool vis[maxn];
int dis[maxn]; 

int to[maxn<<2],val[maxn<<2],head[maxn],nxt[maxn<<2];
int cnt;

void add_edge(int a,int b,int v){
    to[++cnt]=b;
    nxt[cnt]=head[a];
    head[a]=cnt;
    val[cnt]=v;
}

bool spfa(int u){
    vis[u]=1;
    for(int i=head[u];i;i=nxt[i])
        if(dis[to[i]]>dis[u]+val[i]){
            dis[to[i]]=dis[u]+val[i];
            if(vis[to[i]])return 0;
            if(!spfa(to[i]))return 0;
        }
    vis[u]=0;
    return 1;
}

int main(){
    int n,m1,m2;
    int v,cmd;
    int a,b;
    cin>>n>>m1>>m2;	
    for(int i=1;i<=n;i++) dis[i]=INF;
    for(int i=0;i<m1;i++){
    	cin>>a>>b>>v;
        add_edge(a,b,v);
    }
    for(int i=0;i<m2;i++){
    	cin>>a>>b>>v;
    	add_edge(b,a,-v);
	}
  // for(int i=1;i<=n;i++) add_edge(0,i,0);
    dis[1]=0;
   	if(!spfa(1)) cout<<-1<<endl;
   	else if(dis[n]==INF) cout<<-2<<endl;
   	else cout<<dis[n]<<endl;
    //else cout<<"No\n";
    return 0;
} 
全部评论

相关推荐

昨天 11:04
已编辑
北方民族大学 前端工程师
“无名小卒还是名扬天下?”我知道很多人都不觉得我能走到今天这一步,当然,也包括我自己。在我的人生里,有两部作品刻下了最深的印记:《斗破苍穹》与《龙族》。这两部书总被人拿来对照:一边是萧炎的桀骜轻狂,一边是路明非的怯懦衰颓。有人说,天蚕土豆没见过魂天帝,但江南见过真凯撒。我时常觉得自己就是那个衰小孩路明非,可路明非可以开挂,我不可以;我也无数次幻想过能拥有萧炎那般年少轻狂的人生,可我没有他与生俱来的逆天天赋。我只是个平庸的普通人,一个看过《斗破苍穹》却开不了挂的路明非,只能一步一步往上爬。从我下定决心找实习的那一刻起,我就给自己定下了目标:我一定要为字节跳动卖命.jpg。萧炎有他的三年之约,我有我的两年半之约(其实是一年半)。2024.11.20,科大讯飞的第一封实习offer落进邮箱,我迈出了这场奔赴的第一步。2025.8.18,放弃百度转正的安稳机会,转身走进前路未卜的不确定里。我很感谢我在百度的mentor,是她从茫茫人海选中了我,给了我大厂实习的机会。即便那段时间我状态差、产出不理想,她依旧愿意认可我、希望我留下转正。2025.11.14,我选择走进字节跳动,以实习生的身份重新出发,放下过往,清零重来,只为奔赴心之所向。2026.3.25&nbsp;-&nbsp;3.27,三天速通上海飞书,斩获Special&nbsp;Offer。被告知面试通过的那一刻,我的内心无比平静,就像这个offer本就该属于我。不是侥幸,是应得的。这一路,有人看轻过我的出身,不相信我能走到这里;也有人在我看不见前路的时候,替我举过灯。没有他们的鼓励与支撑,就没有今天站在这里的我。我看到了自强不息的激荡,那是一个双非的伟大乐章!我是雨夜迈巴赫,我要开启属于我的新篇章了。
在看牛客的本杰明很勇...:真心祝贺l总 我永远的偶像 我滴神
春招至今,你收到几个面试...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务