题目:

不难看出题意主要是给出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],于是可以联想到最短路模型中的一部分代码

  1. if(dis[u]+w(u,v)<=dis[v])
  2. {
  3. dis[v]=dis[u]+w(u,v);
  4. }

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

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

上面的代码要实现的是使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分的

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define INF 0x3f3f3f3f
  4. const int N=1005;
  5. const int M=40005;
  6. int n,ml,md;
  7. struct EDGE{
  8. int next,to,w;
  9. }edge[M];
  10. int head[N],tot;
  11. void add(int x,int y,int v){
  12. edge[++tot].next=head[x];
  13. edge[tot].to=y;
  14. edge[tot].w=v;
  15. head[x]=tot;
  16. }
  17. queue<int> q;
  18. int vis[N],dis[N],circle[N];//circle为指向tt的个数
  19. void spfa(int s){
  20. memset(dis,0x3f,sizeof(dis));
  21. memset(vis,0,sizeof(vis));
  22. memset(circle,0,sizeof(circle));
  23. q.push(s);
  24. vis[s]=1,dis[s]=0;
  25. while(!q.empty()){
  26. int now=q.front();
  27. q.pop();
  28. vis[now]=0;
  29. for(int i=head[now];i;i=edge[i].next){
  30. int tt=edge[i].to;
  31. if(dis[now]+edge[i].w<dis[tt]){
  32. dis[tt]=dis[now]+edge[i].w;
  33. circle[tt]=circle[now]+1;
  34. if(circle[tt]>=n){//指向tt的边超过n个自然是不满足条件的
  35. puts("-1");exit(0);
  36. }
  37. if(!vis[tt]){
  38. vis[tt]=1;
  39. q.push(tt);
  40. }
  41. }
  42. }
  43. }
  44.  
  45. }
  46. int main(){
  47. scanf("%d%d%d",&n,&ml,&md);
  48. for(int i=1;i<=ml;i++){
  49. int a,b,d;
  50. scanf("%d%d%d",&a,&b,&d);
  51. add(a,b,d);//a-b<=d
  52. }
  53. for(int i=1;i<=md;i++){
  54. int a,b,d;
  55. scanf("%d%d%d",&a,&b,&d);
  56. add(b,a,-d);//b-a>=d ==> a-b<=-d
  57. }
  58. spfa(1);
  59. if(dis[n]>1e8){puts("-2");return 0;}
  60. printf("%d",dis[n]);
  61. return 0;
  62. }

AC代码

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int n,ml,md,a,b,c,fst[10100],nex[50010],v[50010],w[50010],cnt,vis[10100],dis[10100],tim[10100];
  4. queue<int> q;
  5. void add(int a,int b,int c)
  6. {
  7. nex[++cnt]=fst[a];
  8. fst[a]=cnt;
  9. v[cnt]=b;
  10. w[cnt]=c;
  11. return ;
  12. }
  13. int spfa(int k)
  14. {
  15. memset(dis,0x7f/3,sizeof(dis));
  16. memset(vis,0,sizeof(vis));
  17. memset(tim,0,sizeof(tim));
  18. q.push(k);
  19. dis[k]=0;
  20. vis[k]=1;
  21. while(!q.empty())
  22. {
  23. int u=q.front();
  24. //cout<<u<<" ";
  25. q.pop();
  26. tim[u]++;
  27. vis[u]=0;
  28. if(tim[u]>n)
  29. return -1;
  30. for(int i=fst[u];i!=-1;i=nex[i])
  31. {
  32. if(dis[v[i]]>dis[u]+w[i])
  33. {
  34. dis[v[i]]=dis[u]+w[i];
  35. if(!vis[v[i]])
  36. {
  37. q.push(v[i]);
  38. vis[v[i]]=1;
  39. }
  40. }
  41. }
  42. }
  43. /*cout<<endl;
  44. for(int i=1;i<=n;i++)
  45. {
  46. cout<<dis[i]<<" ";
  47. }*/
  48. if(dis[n]>1e8)
  49. return -2;
  50. return dis[n];
  51. }
  52. int main()
  53. {
  54. memset(fst,-1,sizeof(fst));
  55. cin>>n>>ml>>md;
  56. for(int i=1;i<=ml;i++)
  57. {
  58. scanf("%d%d%d",&a,&b,&c);
  59. add(a,b,c);
  60. }
  61. for(int i=1;i<=md;i++)
  62. {
  63. scanf("%d%d%d",&a,&b,&c);
  64. add(b,a,-c);
  65. }
  66. for(int i=1;i<n;i++)
  67. {
  68. add(i+1,i,0);
  69. }
  70. for(int i=1;i<=n;i++)
  71. {
  72. add(0,i,0);
  73. }
  74. int sp=spfa(0);
  75. if(sp<=-1)
  76. {
  77. cout<<sp;
  78. return 0;
  79. }
  80. else
  81. {
  82. cout<<spfa(1);
  83. }
  84. //cout<<" "<<sp;
  85. return 0;
  86. }

  

代码参考: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. django--没有整理,笔记

    https://docs.djangoproject.com/en/2.2/常用的数据路命令:python manage.py makemigrations 数据移植准备python manage.p ...

  2. Oracle 多表联合删除?--转

    oracle和mysql多表删除数据的方法一大把,好多都是没经过证实的,你很可能已经被错误信息误导了,下面我以mysql两张表删除数据为例,来让给为注意到这一点,我在mysql中新建了两张表,分别是用 ...

  3. 13、Spring Boot 2.x 多数据源配置

    1.13 Spring Boot 2.x 多数据源配置 完整源码: Spring-Boot-Demos

  4. springboot与springcloud区别:

  5. 第一次Java测试及感触(2018.9.20)

    在本周周四进行了java测试,有一点感触,测试的题目是用Java实现一个ATM机的管理系统.之前老师提前给我们样卷,结果考试的时候换了题型,瞬间脑子空白,一时不知道怎么下手,因为暑假虽然涉猎了java ...

  6. 学习GeoServer遇到的问题及答案

    简介:本文的记录学习GeoServer遇到的问题,如果已有答案将会附上. 1.GeoServer介绍?,功能? GeoServer 是 OpenGIS Web 服务器规范的 J2EE 实现,利用 Ge ...

  7. servlet多线程安全问题

    Servelet多线程安全问题 原因 一个servlet被实例化一次,当有多个用户访问时,多个线程会访问同一个实例,实例变量就会被不同的用户修改. 简单的案例 新建servlet,访问http://l ...

  8. Oracle JDBC 连接池

    1.简介 数据库连接池负责分配.管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个:释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据 ...

  9. Flutter用dio封装http网络请求,设置统一的请求地址、headers及处理返回内容

    封装http请求是项目中经常需要做的,常用于设置通用请求地址.请求headers以及处理返回结果,例如在项目中开发地址.测试地址.上线地址是不一样的,当在封装的请求设置好默认地址之后只需要改一个地址而 ...

  10. 如何卸载oracle11g

    方法/步骤   .关闭oracle所有的服务.可以在windows的服务管理器中关闭:   打开注册表:regedit 打开路径:HKEY_LOCAL_MACHINE\SYSTEM\CurrentCo ...