POJ-2983 用Bellman-Ford求解差分约束..

本文深入探讨了差分约束的概念及其在解决特定类型不等式组问题中的应用,通过实例展示了如何利用Bellman-Ford算法解决此类问题,并详细解释了解决过程中可能出现的无解情况及判断方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

差分约束就是一推
a1-a2<=k1
a2-a3<=k2
a3-a1<=k3
.....
之类的不等式组...求解差分约束也就是求解其中的一个解...如果能得到一组解..那么所有的数加同一个数那么不等式显然是成立的...也就是每个数可以取到任意值..那就确定一个数,来求出一组解..假设先给 a[ s] 一个初值...d [ s ] [ v ] 代表当 a [ s ] 为这个确定值时 a [ v ] 可以为的数...w [ u ] [ v ] 是值 u 与 v 之间的关系...如 av-au=k 则 w [ u ] [ v ] = k...可以通过反证法推倒出:
d [ s ] [ v ] <= d [ s ] [ u ] + w [ u ] [ v ]
这个式子就容易想到 Bellman-Ford 里的 Relax 过程了..于是乎可以将差分约束问题通过构图再用Bellman-Ford解决...图中的点就是 a1,a2...an 图中的边就是点之间的关系...如果 ai-aj=k 则有边 w [ j ] [ i ] = k..但大部分的不等式组不仅仅是小于等于关系...可能有大于等于..等于...>=很好处理..两边同时乘以-1就可以了...等于的情况..就把等于拆成两个不等式...例如ai-aj=k..则拆成 ai-aj<=k , aj-ai<=-k .. 显然这两个不等式的唯一解就是 ai-aj..但把其拆成了小于等于关系...符合差分约束的条件...
定任意一个点为原点...值也可以是任意值...然后做一次Bellman-Ford..得出的 d [ i ] 就是在这组解中ai的值...
但这里有个很大的问题,就是无解的情况,例如 a1-a2<=1 , a2-a1<=1 这种情况明显不可能有解...那在用Bellman-Ford中的情况就是存在负环...那么只要在做完Bellman-Ford再判断一下有没有负环就可以了...
具体的一道题POJ-2983,是给出一些点的位置关系...有确定的也有模糊的...问这些信息是不是没有矛盾是正确的..
很典型的差分约束问题...确定的情况转化为两个不确定的情况做两条边..模糊的情况就直接做边...然后用Bellman-Ford求解...再判断有没有负环..有负环就代表该不等式组无解..输出Unreliable..无负环代表有解~~这组信息可以推断出一组位置关系..则输出Reliable...
这道题要注意的就是...模糊关系时给的>=1..所以要记得转化成小于等于...这里没注意WA了好久...囧

Ps: 是<=..不是<..<的话要化成 <=k-1 !!!

Program:

#include<iostream> using namespace std; struct pp { int x,y,k; }line[300001]; int n,m,i,x,y,k; char c; bool Bellman_Ford() { int i,times,d[1001]; memset(d,0x7F,sizeof(d)); d[1]=0; for (times=1;times<=n;times++) for (i=1;i<=m;i++) if (d[line[i].y]>d[line[i].x]+line[i].k) d[line[i].y]=d[line[i].x]+line[i].k; for (i=1;i<=m;i++) if (d[line[i].y]>d[line[i].x]+line[i].k) return false; return true; } int main() { while (~scanf("%d%d",&n,&m)) { i=m; m=0; while (i--) { c=getchar(); while (c!='V' && c!='P' ) c=getchar(); ; if (c=='P') { scanf("%d%d%d",&y,&x,&k); m++; line[m].x=x; line[m].y=y; line[m].k=k; m++; line[m].x=y; line[m].y=x; line[m].k=-k; }else { scanf("%d%d",&x,&y); m++; line[m].x=x; line[m].y=y; line[m].k=-1; } } if (Bellman_Ford()) printf("Reliable\n"); else printf("Unreliable\n"); } return 0; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值