POJ 1716 Integer Intervals

题意:给出一些区间,求一个集合的长度要求每个区间里都至少有两个集合里的数。

 

解法:贪心或者差分约束。贪心的思路很简单,只要将区间按右边界排序,如果集合里最后两个元素都不在当前区间内,就把这个区间内的最后两个数加入集合,如果只有一个元素在区间里就加一个,如果两个元素都在区间里就不加。

差分约束系统用来解一个不等式组,只要这个不等式组里的不等式形如x1 - x2 <= c,c为常数就可以用差分约束来解不等式,将每个变量看做点,每个不等式看做边,求一个最短路,那么dis[i]就是不等式的一组解,主要利用的原理就是在最短路问题中:dis[v] <= dis[u] + edge[u][v],而将x1 - x2 <= c进行移项就可以得到以上形式,由于有负权,所以一般用bellmanford或者spfa……不过我不会写spfa……如果产生负环说明无解。

对于本题来说,将每个区间端点都看做点,sum[i]表示集合中小于等于i的数的个数,则对于一个区间[l, r]来说有不等式sum[r] - sum[l - 1] >= 2,转化成上述形式就是sum[l - 1] - sum[r] <= -2,可以看做是点r到点l-1的一条权值为-2的边。除了题中给出的条件,还有一个隐含条件为0 <= sum[i] - sum[i - 1] <= 1,用以上不等式建图后跑最短路,dis[n] - dis[0]即为答案。

差分约束比较复杂……但是主要想练差分约束才做的这题= =但是数据范围略大……跑bellmanford有点难……最后1000ms擦边过的……

 

代码:

贪心:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<math.h>
#include<limits.h>
#include<time.h>
#include<stdlib.h>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#include<iomanip>
#define LL long long
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1

using namespace std;

struct node
{
    int l, r;
    bool operator < (const node &tmp) const
    {
        if(r == tmp.r) return l < tmp.l;
        return r < tmp.r;
    }
}interval[10005];
int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        for(int i = 0; i < n; i++)
            scanf("%d%d", &interval[i].l, &interval[i].r);
        sort(interval, interval + n);
        int x = -1, y = -1;
        int ans = 0;
        for(int i = 0; i < n; i++)
        {
            if(interval[i].l <= x) continue;
            if(interval[i].l <= y)
            {
                x = y;
                y = interval[i].r;
                ans++;
                continue;
            }
            x = interval[i].r - 1;
            y = interval[i].r;
            ans += 2;
        }
        cout << ans << endl;
    }
    return 0;
}

  

差分约束系统:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<math.h>
#include<limits.h>
#include<time.h>
#include<stdlib.h>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#include<iomanip>
#define LL long long
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1

using namespace std;

struct node
{
    int u, v, value;
    node(int u, int v, int value) : u(u), v(v), value(value) {}
    node() {}
}edge[30005];
int minn = 10000000, maxn, m, cnt;
int dis[10005];
const int inf = 0x3f3f3f3f;
void BellmanFord()//由于不存在无解的数据,不需要判负环
{
    memset(dis, 0, sizeof dis);
    dis[minn] = 0;
    bool flag = true;
    while(flag)//剪枝,如果本次没有进行松弛,则停止松弛
    {
        flag = false;
        for(int j = 0; j < cnt; j++)
            if(dis[edge[j].v] > dis[edge[j].u] + edge[j].value)
            {
                flag = true;
                dis[edge[j].v] = dis[edge[j].u] + edge[j].value;
            }
    }
}
int main()
{
    while(~scanf("%d", &m))
    {
        cnt = 0;
        for(int i = 0; i < m; i++)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            minn = min(minn, min(a, b + 1));//记录最小点
            maxn = max(maxn, max(a, b + 1));//记录最大点
            edge[cnt++] = node(b + 1, a, -2);
        }
        for(int i = minn + 1; i <= maxn; i++)
        {
            edge[cnt++] = node(i - 1, i, 1);
            edge[cnt++] = node(i, i - 1, 0);
        }
        BellmanFord();
        cout << dis[maxn] - dis[minn] << endl;
    }
    return 0;
}

  

posted @ 2015-10-15 12:38  露儿大人  阅读(229)  评论(0编辑  收藏  举报