题目:

不难看出题意主要是给出ml+md个格式为xi-xj<=ak的不等式,xi-xj为i,j俩头牛的距离,要我们求x1-xn的最大值。

经过上下加减我们可以将这几个不等式化成x1-xn<=a1+a2+a3+a4+....+ak,在这加减的过程中我们不难看到dijstra的身影,这加加减减的过程不正是松弛操作吗!

这时我们就得到了正解——差分约束算法,此算法主要用于处理差分约束系统:如果一个系统由n个变量和m个约束条件组成,形成m个形如ai-aj≤k的不等式(i,j∈[1,n],k为常数),则称其为差分约束系统。

结论:求解差分约束系统,都可以转化成图论的单源最短路径(或最长路径)问题。

关于差分约束与最短路模型的关系

我们观察上面例子中的不等式,都是x[i] - x[j] <= a[k],可以进行移项,成为x[i] <= x[j] + a[k],我们令a[k] = w(j, i),dis[i]=x[i],并使i=v,j=u,那么原始就变为:dis[u]+w(u,v)>=dis[v],于是可以联想到最短路模型中的一部分代码

if(dis[u]+w(u,v)<=dis[v])
{
dis[v]=dis[u]+w(u,v);
}

这不正与松弛操作相似吗?

但是好像不等号方向刚好相反,但其实这并不矛盾

上面的代码要实现的是使dis[u]+w(u,v)>dis[v],而对于不等式,我们进行建边的操作:对于每个不等式 x[i] - x[j] <= a[k],对结点 j 和 i 建立一条 j -> i的有向边,边权为a[k],求x[n-1] - x[0] 的最大值就是求 0 到n-1的最短路,两者刚好吻合。所以求解差分约束问题就转化为了最短路问题。

问题解的存在性

由于在求解最短路时会出现存在负环或者终点根本不可达的情况,在求解差分约束问题时同样存在

(1)存在负环

如果路径中出现负环,就表示最短路可以无限小,即不存在最短路,那么在不等式上的表现即X[n-1] - X[0] <= T中的T无限小,得出的结论就是 X[n-1] - X[0]的最大值不存在。在SPFA实现过程中体现为某一点的入队次数大于节点数。(貌似可以用sqrt(num_node)来代替减少运行时间)

(2)终点不可达

这种情况表明X[n-1]和X[0]之间没有约束关系,X[n-1] - X[0]的最大值无限大,即X[n-1]和X[0]的取值有无限多种。在代码实现过程中体现为dis[n-1]=INF。

参考的文章链接:https://blog.csdn.net/my_sunshine26/article/details/72849441

注意

1.因为本题中可能存在负权环(众所周知dijstra在碰到这个玩意时完全没有办法)所以我们需要用到SPFA

2.后md个不等式题目一开始给的是:xj-xi>=a 我们可以推出xi-xj<=-a(这在之后的建图处理中会用到)注意负权边。

3.题目所给的条件不一定是对的,所以我们需要跑两次SPFA判断图是不是联通的。(因为洛谷上有3个坑逼数据)

代码:

此为没有考虑条件不正确的情况的代码,70分(洛谷上),在联赛是应该是100分的

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
const int N=1005;
const int M=40005;
int n,ml,md;
struct EDGE{
int next,to,w;
}edge[M];
int head[N],tot;
void add(int x,int y,int v){
edge[++tot].next=head[x];
edge[tot].to=y;
edge[tot].w=v;
head[x]=tot;
}
queue<int> q;
int vis[N],dis[N],circle[N];//circle为指向tt的个数
void spfa(int s){
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(circle,0,sizeof(circle));
q.push(s);
vis[s]=1,dis[s]=0;
while(!q.empty()){
int now=q.front();
q.pop();
vis[now]=0;
for(int i=head[now];i;i=edge[i].next){
int tt=edge[i].to;
if(dis[now]+edge[i].w<dis[tt]){
dis[tt]=dis[now]+edge[i].w;
circle[tt]=circle[now]+1;
if(circle[tt]>=n){//指向tt的边超过n个自然是不满足条件的
puts("-1");exit(0);
}
if(!vis[tt]){
vis[tt]=1;
q.push(tt);
}
}
}
} }
int main(){
scanf("%d%d%d",&n,&ml,&md);
for(int i=1;i<=ml;i++){
int a,b,d;
scanf("%d%d%d",&a,&b,&d);
add(a,b,d);//a-b<=d
}
for(int i=1;i<=md;i++){
int a,b,d;
scanf("%d%d%d",&a,&b,&d);
add(b,a,-d);//b-a>=d ==> a-b<=-d
}
spfa(1);
if(dis[n]>1e8){puts("-2");return 0;}
printf("%d",dis[n]);
return 0;
}

AC代码

#include<bits/stdc++.h>
using namespace std;
int n,ml,md,a,b,c,fst[10100],nex[50010],v[50010],w[50010],cnt,vis[10100],dis[10100],tim[10100];
queue<int> q;
void add(int a,int b,int c)
{
nex[++cnt]=fst[a];
fst[a]=cnt;
v[cnt]=b;
w[cnt]=c;
return ;
}
int spfa(int k)
{
memset(dis,0x7f/3,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(tim,0,sizeof(tim));
q.push(k);
dis[k]=0;
vis[k]=1;
while(!q.empty())
{
int u=q.front();
//cout<<u<<" ";
q.pop();
tim[u]++;
vis[u]=0;
if(tim[u]>n)
return -1;
for(int i=fst[u];i!=-1;i=nex[i])
{
if(dis[v[i]]>dis[u]+w[i])
{
dis[v[i]]=dis[u]+w[i];
if(!vis[v[i]])
{
q.push(v[i]);
vis[v[i]]=1;
}
}
}
}
/*cout<<endl;
for(int i=1;i<=n;i++)
{
cout<<dis[i]<<" ";
}*/
if(dis[n]>1e8)
return -2;
return dis[n];
}
int main()
{
memset(fst,-1,sizeof(fst));
cin>>n>>ml>>md;
for(int i=1;i<=ml;i++)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
for(int i=1;i<=md;i++)
{
scanf("%d%d%d",&a,&b,&c);
add(b,a,-c);
}
for(int i=1;i<n;i++)
{
add(i+1,i,0);
}
for(int i=1;i<=n;i++)
{
add(0,i,0);
}
int sp=spfa(0);
if(sp<=-1)
{
cout<<sp;
return 0;
}
else
{
cout<<spfa(1);
}
//cout<<" "<<sp;
return 0;
}

  

代码参考:https://www.luogu.org/blog/roy1994/solution-p4878  https://www.luogu.org/blog/mikasamikasa/solution-p4878

差分约束算法————洛谷P4878 [USACO05DEC] 布局的更多相关文章

  1. 洛谷P4878 [USACO05DEC]layout布局

    题目描述 正如其他物种一样,奶牛们也喜欢在排队打饭时与它们的朋友挨在一起.\(FJ\) 有编号为 \(1\dots N\) 的 \(N\) 头奶牛 \((2\le N\le 1000)\).开始时,奶 ...

  2. 【最短路·差分约束】洛谷P1250

    题目描述 一条街的一边有几座房子.因为环保原因居民想要在路边种些树.路边的地区被分割成块,并被编号成1..N.每个部分为一个单位尺寸大小并最多可种一棵树.每个居民想在门前种些树并指定了三个号码B,E, ...

  3. 【洛谷P4878】布局

    题目大意:给定一个长度为 N 的递增序列,有 M 组差分约束关系,求满足这些约束关系时,第一个数和第 N 个数的差是多少. 题解:首先,能否满足约束关系需要判断一下负环,若满足约束关系,再从第一个点 ...

  4. 洛谷 P4878 [USACO05DEC]layout布局

    题面链接 sol:差分约束系统裸题,根据a+b<=c建个图跑个最短路就没了... #include <queue> #include <cstdio> #include ...

  5. P5960 差分约束算法模板

    差分约束 差分约束,一般用来解决有\(n\)个未知数,\(m\)个不等式方程的问题,形如: \[\begin{cases} \ x_{a_1}-x_{b_1}\leq y_1\\ \ x_{a_2}- ...

  6. 鉴于spfa基础上的差分约束算法

    怎么搞?        1. 如果要求最大值      想办法把每个不等式变为标准x-y<=k的形式,然后建立一条从y到x权值为k的边,变得时候注意x-y<k =>x-y<=k ...

  7. P4878 [USACO05DEC] 布局

    题面lalala 这居然是个紫题???原谅我觉得这题是模板... 这个这个,这题的算法呢其实是一个叫差分约束的东西,也是今天下午我们机房的重点,如果不知道这个差分约束是个啥的人呢,自行百度一下谢谢.. ...

  8. Luogu P4878 [USACO05DEC]布局

    题目 差分约束模板. 注意判负环需要建一个超级源点到每个点连一条\(0\)的边.因为\(1\)不一定能到达所有的点. #include<bits/stdc++.h> #define pi ...

  9. P5960 【模板】差分约束算法

    题目描述 给出一组包含 $m$ 个不等式,有 $n$ 个未知数的形如: 的不等式组,求任意一组满足这个不等式组的解. 输入格式 第一行为两个正整数 $n,m$,代表未知数的数量和不等式的数量. 接下来 ...

随机推荐

  1. [唐胡璐]Java操作Sql Server 2008数据库

    下载Microsoft JDBC Driver for SQL Server 直接去官网下载即可: 下载解压文件,得到sqljdbc.jar和sqljdbc4.jar。如果你使用的是jre1.7版本, ...

  2. 第五章 Flask视图高级

    add_url_rule和app.route原理剖析 add_url_rule add_url_rule(rule,endpoint=None,view_func=None) 这个方法用来添加url与 ...

  3. python协程初步---一个迭代器的实现

    一般认为迭代器就是实现了两个方法__iter__和__next__ 先创建这样一个类 from collections import Iterable from collections import ...

  4. Ubuntu 蓝牙鼠标的问题

    问题: 我有一个小巧的蓝牙鼠标,但有一个问题. 当它不使用一段时间时,它会关闭. 好的我得按按钮把它打开. 但是我发现,在我在蓝牙小程序下单击"连接"之前,它不会再被Ubuntu识 ...

  5. CF557E Ann and Half-Palindrome 字典树+dp

    现在看这道题也不难啊,不知道考场上为啥没切~ code: #include <bits/stdc++.h> #define N 5006 #define setIO(s) freopen( ...

  6. 51nod 1503

    动态规划 $f[a][b][c][d]$ 表示从 $(1, 1)$ 走到 $(a, b)$ 和从 $(n, m)$ 走到 $(c, d)$ 的方案数 $f[a][b][c][d]$ $= f[a][b ...

  7. Machine Schedule为什么UVA过了POJ过不了

    UVA1194 POJ1325 POJ要多判一个非零!!! #include<cstdio> #include<vector> #include<cstring> ...

  8. qt 布局管理按钮控件间有空隙?

    定义了几个按钮控件,想要按钮间没有空隙,我使用setspaces(0)来设置它们之间的间隔. 结果控件间还是有空隙,如图 我对控件所在的widget的背景进行设置,(会把style传到子控件)发现结果 ...

  9. CSPS模拟75&76

    感觉自己还是太菜了... 最近考试一直想不出来正解.难受(然而蒟蒻的博客没人看也要不来小猪peiqi的图) 模拟75:血炸... 考场上推了快两个小时的T1式子,然后心态炸裂,然后我也不知道自己干了什 ...

  10. html2canvas原理

    html2canvas有2种模式,一种是利用foreignObject,一种是纯canvas绘制 1.foreignObject到canvas 步骤: 1.把要截图的dom克隆一份,过程中把getCo ...