差分约束
差分约束:
对于差分不等式,a - b <= c ,建一条 b 到 a 的权值为 c 的边,求的是最短路,得到的是最大值
对于差分不等式,a - b >= c ,建一条 b 到 a 的权值为 c 的边,求的是最长路,得到的是最小值
求最短路,值是满足条件约束的最大值。
求最长路,值是满足条件约束的最小值。
最短路:开始的时候,初始化为+无穷。不断减小最短路的值来看是否满足约束条件的,一旦满足约束条件了, 就不再松弛了,这样获得的值就是最大的符合约束的。
最长路:相反就好。
给你一个n元不等式方程组 求其中两个未知量之间的最值
例:
b<=a+3
c<=b+2
c<=a+5 *****注意符号方向一致*****
求c-a的最大值
可以将 a b c看成三个点, b->a c->b c->a看成三条边, 3 2 5看成三个边的权值。
就可以看成是求 点a 到 点c 的最短路径。。。
SPFA算法:(可以判断图是不是存在有向环)
将源点到所有点的距离初始化为无穷大
》设立一个先进先出的队列用来保存待优化的结点,每次取出队首结点u。
》用u点当前的最短路径估计值对u点所指向的结点v进行松弛操作(最短比较)
》如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。
》这样不断从队列中取出结点来进行松弛操作(最短比较),直至队列空为止。
(记录每个节点进行松弛操作的次数,次数等于节点数目时,存在有向环)
/*** 题目大意 ***/
有N各项目,每个项目完成需要时间为time[i],d数组代表每个项目最早的开始时间
四种指令:
SAS a b d[a] <= d[b]
SAF a b d[a] <= d[b]+time[b]
FAF a b d[a]+time[a] <= d[b]+time[b]
FAS a b d[a]+time[a] <= d[b]
是四种约束条件。
***本题SPFA需要一个开始源点,且原点到任意顶点的边的权值都为0
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #define MAX 1e9 #define MAXN 10005 using namespace std; /*** 邻接表结构 ***/ typedef struct arc_data{ int vex, w; struct arc_data *next; } arc_data; struct vex_data{ arc_data *head; } adj[MAXN]; int ti[MAXN]; //记录每个项目完成需要的时间 int n, t; //n顶点个数 t执行次数 int d[MAXN]; //记录每个项目开始时间 void create(int a, int b, int w){ //插入边 arc_data *p; p = new arc_data; p->vex=b; p->w = w; p->next = adj[a].head; adj[a].head=p; } void init(){ //建立邻接表 for(int i=0; i<=n; i++) adj[i].head = NULL; for(int i=1; i<=n; i++) scanf("%d", &ti[i]); char s[100]; while(scanf("%s", s) && s[0]!= '#'){ int a,b; scanf("%d%d", &a, &b); if(strcmp(s, "SAS")==0) create(b, a, 0); if(strcmp(s, "SAF")==0) create(b, a, ti[b]); if(strcmp(s, "FAS")==0) create(b, a, -ti[a]); if(strcmp(s, "FAF")==0) create(b, a, (ti[b]-ti[a])); } for(int i=1; i<=n; i++) create(0, i, 0); } /*** 求存在负权值的最短路径SPFA ***/ bool SPFA(){ int out[n]; //记录顶点的操作次数 bool v[n]; //记录当前队列中存在元素 memset(v, 0, sizeof(v)); memset(out, 0, sizeof(out)); for(int i=0; i<=n; i++) //初始化各点距离无穷小 d[i]= -MAX; queue<int> Q; d[0]=0; Q.push(0); v[0]=true; while(!Q.empty()){ int k=Q.front(); Q.pop(); v[k]=false; out[k]++; if(out[k]>n) return false; //节点操作次数大于n,则邻接表存在有向环 arc_data *p; for(p=adj[k].head; p!=NULL; p=p->next){
if(d[p->vex] < d[k]+p->w){ d[p->vex] = d[k]+p->w; if(!v[p->vex]){ v[p->vex]=true; Q.push(p->vex); } } }
} return true; } void print(){ printf("Case %d:\n", t++); if(!SPFA())
puts("impossible"); else{ for(int i=1; i<=n; i++){
printf("%d %d\n", i, d[i]); }
} } int main(){ t=1; while(scanf("%d",&n) && n){ init(); print(); puts(""); } return 0; }
大意:
有很多高低不同的房子,排在一条线上,从最低的依次跳到最高的,每次可以跳的水平距离D(忽略竖直距离)
》 没有两个房子是在一起的 f[i]-f[i+1] <= -1
》 每次可以跳距离为D f[a]- f[b] <= D(a代表两个相邻高度的房子中下标小的,b带下标大的) 下标 小->大 代表距离
这样建图建图,再进行最高楼与最低楼的下标 小的当做源点 大的当做终点求最短路径就ok~~
#include <cstdio> #include <cstring> #include <stack> #include <queue> #include <algorithm> #include <iostream> using namespace std; #define N 1010 #define MAX 1e9+7 #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) typedef struct arc_data{ int v, w; struct arc_data *next; } arc_data; struct vex_data{ arc_data *head; } vex[N]; struct node{ int id, high; } s[N]; int n, D; bool cmp(const struct node x, const struct node y){ return x.high<y.high; } void create(int a, int b, int w){ //建邻接表 arc_data *p; p = new arc_data; p->v=b; p->w=w; p->next = vex[a].head; vex[a].head=p; } bool init() { scanf("%d%d", &n, &D); for(int i=1; i<=n; i++){ scanf("%d", &s[i].high); s[i].id=i; vex[i].head = NULL; } sort(s+1, s+1+n, cmp); for(int i=1; i<n; i++){ create(i+1, i, -1); //下标相邻的两点距离大于1 int a=max(s[i+1].id, s[i].id); int b=min(s[i+1].id, s[i].id); int temp=a-b; if(temp > D) return false; //高度相邻两点, 下标距离 <= 跳的最大距离 create(b, a, D); } return true; } void SPFA(int s, int t){ queue<int> S; while(!S.empty()) S.pop(); bool in_s[N]; int out_[N], d[N]; arc_data *p; memset(out_, 0, sizeof(out_)); memset(in_s, 0, sizeof(in_s)); for(int i=1; i<=n; i++) { d[i] = MAX; } d[s]=0; S.push(s); in_s[s]=true; while(!S.empty()){ int k=S.front(); S.pop(); in_s[k]=false; out_[k]++; if(out_[k] > n){ printf("-1\n"); return ; } for(p=vex[k].head; p!=NULL; p=p->next){ if(d[p->v] > d[k]+p->w){ d[p->v]=d[k]+p->w; if(!in_s[p->v]){ in_s[p->v]=true; S.push(p->v); } } } } printf("%d\n", d[t]); } int main(){ int t, ti; scanf("%d", &t); for(ti=1; ti<=t; ti++){ bool x = init(); printf("Case %d: ", ti); if(!x){ printf("-1\n"); continue; } int a = min(s[1].id, s[n].id); //找下标相对大小的~~ int b = max(s[1].id, s[n].id); SPFA(a, b); } return 0; }

浙公网安备 33010602011771号