1201 Intervals 差分约束系统

 

鄙人第一个差分约束系统。

看了N多的资料和别人的解题报告,发现下面用BELLMAN FORD 加稍微的剪枝时间可以飙到200MS以内,不错不错。

就是那个FLAG,没了这个就TLE了。。。惨剧啊!!!!

 

另外的话,这个题目的例子是给了5个区间,说5个区间包含了Z数组C个数,接着问你Z数组到底至少有几个数。数组不用连续

 

主要是下面三点

1。s[b]>=s[a-1]+c

2.s[b-1]>=s[b]+(-1)

3.s[b]>=s[b-1]

维护这三个不等式即可,s[]表示从0到x含有的数字的个数

 

如何维护呢?

 

想像一下做图论的时候题目对边的更新。对了!

那个更新和第一个不等式是相似的。

 

注意这种题目使不能用DISTRA算法做的,因为C可能为负值。对应就是不等式可能无解。所以要用BELLMAN FORD。另外对于SPFA,现在还没写,下次写的时候会SHARE

 

还有就是很神奇的就是。如果维护上面第一个不等式,我们得到的解是满足约束的最小值!

那么怎么得到最大值呢?!

很简单,用小于等于!

哇哈好!

 

#include<stdio.h>

struct EDGE

{

    int x,y,v;

}edge[50005];

const int MAXN=1<<30-1;

int n,rmin,rmax,dis[50005];

void bellman()

{

    for(int i=rmin;i<=rmax;i++)  dis[i]=-MAXN;

    dis[rmin]=0;

    for(int i=0;i<rmax-rmin;i++)

    {

        bool flag=false;//剪枝

        for(int j=0;j<n;j++)

        if(dis[edge[j].x]!=-MAXN&&dis[edge[j].y]<dis[edge[j].x]+edge[j].v)//求最小值

        {

            dis[edge[j].y]=dis[edge[j].x]+edge[j].v;

            flag=true;

        }

        for(int j=rmin;j<rmax;j++)

        if(dis[j]!=-MAXN&&dis[j+1]<dis[j])

        {

            dis[j+1]=dis[j];

            flag=true;

        }

        for(int j=rmax;j>rmin;j--)

        if(dis[j]!=-MAXN&&dis[j-1]<dis[j]-1)

        {

            dis[j-1]=dis[j]-1;

            flag=true;

        }

        if(!flag) break;

    }

}

int main()

{

    while(scanf("%d",&n)!=EOF)

    {

        rmin=MAXN;

        rmax=-1;

        for(int i=0;i<n;i++)

        {

            int a,b,c;

            scanf("%d%d%d",&a,&b,&c);

            b++;

            edge[i].x=a;

            edge[i].y=b;

            edge[i].v=c;

            if(a<rmin) rmin=a;

            if(b>rmax) rmax=b;

        }

        bellman();

        printf("%d/n",dis[rmax]);

    }

    return 0;

}

 

 

并且由于另外两个不等式只和点有关,如果我都把他们构造成了边,那么就TLE了,看来SPFA还是稳定很多啊

#include<stdio.h>

const int E=50005;

const int V=50005;

const int INF=1<<25-1;

struct EDGE

{

    int u,v,val;

}edge[E*4];

int e,rmin,rmax,dist[V];

void addedge(int a,int b,int c)

{

    edge[e].u=a;

    edge[e].v=b;

    edge[e++].val=c;

}

int bellman()

{

    for(int i=rmin;i<=rmax;i++)  dist[i]=-INF;

    dist[rmin]=0;

    //for(int i=rmin;i<=rmax;i++)

    for(int i=0;i<rmax-rmin;i++)

    {

        bool flag=false;

        for(int j=0;j<e;j++)

        if(dist[edge[j].u]!=-INF&&dist[edge[j].v]<dist[edge[j].u]+edge[j].val)

        {

            dist[edge[j].v]=dist[edge[j].u]+edge[j].val;

            flag=true;

        }

        if(!flag)  break;

    }

    return dist[rmax]-dist[rmin];

}

int main()

{

    int n;

    while(scanf("%d",&n)!=EOF)

    {

        e=0;

        rmin=INF;

        rmax=-1;

        for(int i=1;i<=n;i++)

        {

            int a,b,c;

            scanf("%d%d%d",&a,&b,&c);

            b++;

            if(a<rmin)  rmin=a;;

            if(b>rmax)  rmax=b;

            addedge(a,b,c);

        }

        for(int i=rmin+1;i<=rmax;i++)

        {

            addedge(i-1,i,0);

            addedge(i,i-1,-1);

        }

        printf("%d/n",bellman());

    }

    return 0;

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值