差分约束

  刚学了差分约束系统。

  差分约束就是给你一堆不等式,求一个满足条件的解。比如x-y>=z,x-y<=z这些。对于大于等于的,我们可以转化为从y到x的单向最长路径,小于等于的则是最短路径。我们还要努力找到题目中的隐藏条件,或者自己建立一个原点什么的,这样才可以做。要注意的是,差分约束系统中通常会出现负数,也就是转化后变成负边权,所以不可以用Dijkstra,那我们就用SPFA就好了。

  POJ1201为模板题。

#include <cstdio>
#include <cstring>
#define MS(a,b) memset(a,b,sizeof(a))
#define FOR(i,x,y) for(int i=x;i<=y;++i)
const int o=50010;
int ans,st,en,n,m,a,b,c,k,head,tail,itr,map1[o],dis[o],point[o];
bool vis[o];
struct EDGE//邻接表
{
    int v,w,next;
}edge[o*3];
void addedge(int s,int v,int w)
{
    edge[itr].v=v;
    edge[itr].w=w;
    edge[itr].next=map1[s];
    map1[s]=itr++;
}
int spfa(int st,int en)
{
    FOR(i,st,en) dis[i]=0xc0c0c0c0;//表示与起点的距离
    dis[st]=0; point[1]=st; head=1; tail=0; vis[st]=true;//队列准备
    while(tail!=head)
    {
        tail=(tail+1)%o;//循环队列
        k=point[tail];
        vis[k]=false;//该地点用过后出队
        for(int i=map1[k];i!=-1;i=edge[i].next) if(dis[edge[i].v]<dis[k]+edge[i].w)//最短路
        {
            dis[edge[i].v]=dis[k]+edge[i].w;
            if(!vis[edge[i].v])
            {
                head=(head+1)%o;
                point[head]=edge[i].v;
                vis[edge[i].v]=true;
            }
        }
    }
    return dis[en];
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        MS(edge,0); MS(map1,-1); MS(point,0); MS(vis,0);
        st=0x3f3f3f3f; en=0; itr=0;
        FOR(i,1,n)
        {
            scanf("%d%d%d",&a,&b,&c);
            addedge(a-1,b,c);
            if(st>a) st=a-1;
            if(en<b+1) en=b;
        }
        FOR(i,st,en)
        {
            addedge(i,i+1,0);
            addedge(i+1,i,-1);
        }
        ans=spfa(st,en);
        printf("%d\n",ans);
    }
    return 0;
}

  

你可能感兴趣的:(差分约束)