POJ1201

Problem: Intervals
Description: 给你N个区间,每个区间都有一个C,C表示区间中至少要有C个数字,现在问你至少要多少个数字才能满足所有的区间条件。
Solution_1: 差分约束系统。先看这个问题,如果这些区间都不重叠的话,那么这个问题就很简单。但是并不是这样的,对于区间和问题我们总喜欢表示成这样的形式 T[b]T[a1]>=C 。题中有很多这样的条件,那么是不是很像差分约束系统,这样我们就转化成求0到区间端点的最长路。这样的最长路就是题目中的所求了。但是要注意的是,这里是求最长路,与求最短路不一样,还有当有这些条件是不行的,因为这样无法保证这个图是连通的。我们得从题目中提取些不等式出来,对了就是 T[x]T[x1]>=0T[x1]T[x]>=1 。有了这些条件后,就是简单的差分约束求最长路了, spfa 就好。
Solution_2: 贪心+树状数组,或者再优化些加上并查集。我们知道,对于区间排好序后,我们一个个区间遍历,数字越放到区间右端点的方向越容易被下一个区间覆盖,这样就可以减少数字的数量了。这里用到树状数组是因为要对 [1,X] 这段区间进行求和。众所周知树状数组是基于二分的,所以速度很快。那么并查集又是怎么回事呢?这也是我看到Discuss中的一个大神用的优化,真的是开眼了,学到了并查集的新用法。这里用并查集是来解决判重问题的,大家注意,如果不用并查集,那么就要用一个 used 数组来标识这个点是不是有数字了,但是如果用并查集的话我们每次 search 后把它挂到它前一个点上,那么下次 search 的时候直接就找到了没有数字并且最后的一个点。这样完美的解决了用 used 数组要从后先前遍历的问题。

这里有一点要注意,就是区间的排序,之前我一直都是按左端点作为首关键字排序的,所以一直WA。后来在洗澡的时候突然想到了按左端点排序有可能出现反例。看这样的一组数据:

  • 2
  • 1 100 1
  • 4 8 1

我们按左端点排序得到 [1,100],[4,8] 。由上面的解法,我们会在100这个点填上数字,然后在8这个点填上数字。这样明显不是最优的。那我们按右端点排序得到 [4,8],[1,100] 。我们在8这个点填上数字,然后查询下 [1,100] 有1个数字了,因此不用填了,因此最优答案是1。

Code(差分约束):

#include 
#include 
#include 

#include 
#include 

#define MAX(a,b) ((a)>(b)? (a):(b))
#define MIN(a,b) ((a)<(b)? (a):(b))

using namespace std;

const int M=4*50000+5;

const int INF=0x3f3f3f3f;

typedef struct tagNode{
    int to,c;
    int next;
}Node;

Node map[M];
int head[M];
int top,but,m;
int I;

int dis[M];
int de[M];
bool used[M];

void add_edge(int from,int to,int c)
{
    map[I].to=to;
    map[I].c=c;
    map[I].next=head[from];
    head[from]=I++;
}

bool spfa(int src)
{
    for(int i=0;i0,used[i]=false;
    queue<int> que;
    que.push(src);
    de[src]=1;
    used[src]=true;
    dis[src]=0;

    while(!que.empty()){
        int pre=que.front();
        que.pop();
        used[pre]=false;
        for(int i=head[pre];i+1;i=map[i].next){
            int tmp=map[i].to;
            if(dis[tmp]map[i].c){
                dis[tmp]=dis[pre]+map[i].c;
                if(!used[tmp]){
                    used[tmp]=true;
                    que.push(tmp);
                    ++de[tmp];
                    if(de[tmp]>top)
                        return false;
                }
            }
        }
    }
    return true;
}

int main()
{
    while(cin>>m){
        int a,b,c;
        top=-INF;
        but=INF;
        I=0;
        for(int i=0;i1;
        while(m--){
            scanf("%d%d%d",&a,&b,&c);
            add_edge(a-1,b,c);
            top=MAX(b,top);
            but=MIN(a-1,but);
        }
        for(int i=but+1;i<=top;i++)
            add_edge(i-1,i,0),
            add_edge(i,i-1,-1);
        spfa(but);
        cout<return 0;
}

Code(贪心+树状数组+ used 数组):

#include 
#include 

#include 
#include 

#define MAX(a,b) ((a)>(b)? (a):(b))
#define MIN(a,b) ((a)<(b)? (a):(b))

using namespace std;

const int M=50000+50;

typedef struct tagNode{
    int a,b;
    int c;
}Node;

int m;

int a[M];
bool used[M];

Node qu[M];

int top;

bool cmp(Node a,Node b)
{
    if(a.b!=b.b)
        return a.breturn a.aint lowbit(int x)
{
    return x&(-x);
}

void update(int x)
{
    for(int i=x;i<=top;i+=lowbit(i))
        ++a[i];
}

int find(int x)
{
    int sum=0;
    for(int i=x;i>0;i-=lowbit(i))
        sum+=a[i];
    return sum;
}

int work()
{
    memset(used,false,sizeof(used));
    int ans=0;
    for(int i=1;i<=m;i++){
        int sum=find(++qu[i].b)-find(++qu[i].a-1);
        if(sumint tmp=qu[i].c-sum;
            ans+=tmp;
            for(int j=qu[i].b;j>=qu[i].a&&tmp;j--)
                if(!used[j])
                    update(j),used[j]=true,--tmp;
        }
    }
    return ans;
}

int main()
{
    while(~scanf("%d",&m)){
        top=-1;
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&qu[i].a,&qu[i].b,&qu[i].c),
            top=MAX(qu[i].b+1,top);
        memset(a,0,sizeof(a));
        sort(qu+1,qu+m+1,cmp);
        int ans=work();
        printf("%d\n",ans);
    }
    return 0;
}

Code(贪心+树状数组+并查集):

#include 
#include 

#include 
#include 

#define MAX(a,b) ((a)>(b)? (a):(b))
#define MIN(a,b) ((a)<(b)? (a):(b))

using namespace std;

const int M=50000+50;

typedef struct tagNode{
    int a,b;
    int c;
}Node;

int m;

int a[M];

int p[M];

Node qu[M];

int top;

bool cmp(Node a,Node b)
{
    if(a.b!=b.b)
        return a.breturn a.aint lowbit(int x)
{
    return x&(-x);
}

void update(int x)
{
    for(int i=x;i<=top;i+=lowbit(i))
        ++a[i];
}

int find(int x)
{
    int sum=0;
    for(int i=x;i>0;i-=lowbit(i))
        sum+=a[i];
    return sum;
}

int search(int x)
{
    return x==p[x]? x:p[x]=search(p[x]);
}

int work()
{
    for(int i=0;iint ans=0;
    for(int i=1;i<=m;i++){
        int sum=find(++qu[i].b)-find(++qu[i].a-1);
        if(sumint tmp=qu[i].c-sum;
            ans+=tmp;
            for(int now=qu[i].b;tmp;--tmp){
                now=search(now);
                update(now);
                p[now]=now-1;
                --now;
            }
        }
    }
    return ans;
}

int main()
{
    while(~scanf("%d",&m)){
        top=-1;
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&qu[i].a,&qu[i].b,&qu[i].c),
            top=MAX(qu[i].b+1,top);
        memset(a,0,sizeof(a));
        sort(qu+1,qu+m+1,cmp);
        int ans=work();
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(OJ,ACM算法竞赛)