差分约束

差分约束:
对于差分不等式,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;
}

 

posted @ 2015-09-22 15:16  马晨  阅读(81)  评论(0)    收藏  举报