差分约束详解,详解!!!hdoj 1384

来源:互联网 发布:淘宝家具店铺排行榜 编辑:程序博客网 时间:2024/06/03 20:24
             今天看了下最短路径相关的查分约束,感觉自己理解了一点点,
             想把今天学的记录下,也希望小伙伴指出不足之处!!嘻嘻嘻!
   查分约束:
                就是给出一些形如x-y<=b不等式的约束,问你是否满足有解的问题!
        但是就是在这里比较难以转化!
(建图问题)
给出道题目进行讲解: http://acm.hdu.edu.cn/showproblem.php?pid=1384
题意:有n个区间,给出每个区间的左端点和右端点以及在该区间至少有多少个数在集合Z里面,
            现在让你求出集合Z里面最少元素个数
            思路: MAX,MIN分别代表区间的右端点和左端点,dist[i]存储从源点到某点i的最短路
下面的是自己总结的两种方法:(注意<,>方向)
(1)对于差分不等式,b-a <= c ,建一条 b 到 a 的权值为 -c 的边,求的是最短路,得到的是最大值
首先定义一个数组dist[i],存放的i是:从源点到某点i的最短路,b-a >= c转化a-b<=-c,题目中还有一个隐藏条件

0<=dist[i+1]-dist[i]<=1;转化为dist[i+1]-dist[i]<=1, dist[i]-dist[i+1]<=0;再用邻接表进行建图!


                 b-a>=c        -->       a-b<=-c类型!!

        代码    :

               

#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>using namespace std;#include<queue>#define  INF 0xffffff#define  N  50000+100int  MAX=-1,top=0,T;int MIN=INF;int head[N],visit[N],dist[N];struct Edge{    int  from;    int  to;    int  weight;    int  next; }edge[N*(N-1)/2];void  addEdge(int u,int  v,int w){    edge[top].from =u;    edge[top].to =v;    edge[top].weight =w;    edge[top].next =head[u];    head[u]=top++;}void  init(){    top=0;    memset(head,-1,sizeof(head));    }void  Getp(){        int  a,b,c,i,j;        for(i=1;i<=T;i++)        {            scanf("%d%d%d",&a,&b,&c);            MAX=max(MAX,b);            MIN=min(MIN,a);            addEdge(b,a-1,-c);//反向建图 权值为-c ,a-b<=-c         }        for(i=MIN;i<=MAX;i++)//隐藏条件!         {            addEdge(i,i-1,0);//dist[i]-dist[i+1]<=0            addEdge(i-1,i,1);// dist[i+1]-dist[i]<=1        }}void  spfa(){    int i,j;    queue <int > Q;    Q.push(MAX);    for(i=MIN-1;i<=MAX;i++)    dist[i]=i==MAX?0:INF;    memset(visit,0,sizeof(visit));    visit[MAX]=1;    while(!Q.empty())    {        int  q=Q.front();        Q.pop();        visit[q]=0;        for(i=head[q];i!=-1;i=edge[i].next )        {            int u=edge[i].to ;            if(dist[u]>dist[q]+edge[i].weight )            {                dist[u]=dist[q]+edge[i].weight ;                if(!visit[u])                {                    visit[u]=1;                    Q.push(u);                }            }        }    }    printf("%d\n",-dist[MIN-1]);//从源点《最大》到MIN-1之间 ,即到MIN的最短路径 }int main(){    while(scanf("%d",&T)!=EOF)    {        init();        Getp();        spfa();    }    return  0;} 
(2)<对于不等式 a - b>= c ,建一条 b 到 a 的权值为 c 的边,求的是最长路,得到的是最小值>
和前面的有建图时的权值有差别,主要是源点建立不同,注意!

   

  b-a<=c     --->      a-b>=-c       ,如果方向合适b-a>=c时,无需变化!

  

代码:

      

#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>using namespace std;#include<queue>#define  INF 0xffffff#define  N  50000+100int  MAX=-1,top=0,T;int MIN=INF;int head[N],visit[N],dist[N];struct Edge{int  from;int  to;int  weight;int  next; }edge[N*(N-1)/2];void  addEdge(int u,int  v,int w){edge[top].from =u;edge[top].to =v;edge[top].weight =w;edge[top].next =head[u];head[u]=top++;}void  init(){top=0;memset(head,-1,sizeof(head));}void  Getp(){    int  a,b,c,i,j;for(i=1;i<=T;i++){scanf("%d%d%d",&a,&b,&c);b++;MAX=max(MAX,b);MIN=min(MIN,a);addEdge(a,b,c);}for(i=MIN;i<MAX;i++)//隐藏条件! {addEdge(i+1,i,-1);addEdge(i,i+1,0);}}void  spfa(){int i,j;queue <int > Q;Q.push(MIN);for(i=MIN;i<=MAX;i++)dist[i]=i==MIN?0:-INF;memset(visit,0,sizeof(visit));visit[MIN]=1;while(!Q.empty()){int  q=Q.front();Q.pop();visit[q]=0;for(i=head[q];i!=-1;i=edge[i].next ){int u=edge[i].to ;if(dist[u]<dist[q]+edge[i].weight ){dist[u]=dist[q]+edge[i].weight ;if(!visit[u]){visit[u]=1;Q.push(u);}}}}printf("%d\n",dist[MAX]);}int main(){while(scanf("%d",&T)!=EOF){init();Getp();spfa();}return  0;} 

 

0 1
原创粉丝点击