[差分约束] 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;
} 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值