POJ 1201 & HDU1384 & ZOJ 1508 Intervals(差分约束+spfa 求最长路径)

来源:互联网 发布:视频矩阵和硬盘录像机 编辑:程序博客网 时间:2024/05/22 05:02

题目链接:

POJ:http://poj.org/problem?id=1201

HDU:http://acm.hdu.edu.cn/showproblem.php?pid=1384

ZOJ:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=508

Description

You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn. 
Write a program that: 
reads the number of intervals, their end points and integers c1, ..., cn from the standard input, 
computes the minimal size of a set Z of integers which has at least ci common elements with interval [ai, bi], for each i=1,2,...,n, 
writes the answer to the standard output. 

Input

The first line of the input contains an integer n (1 <= n <= 50000) -- the number of intervals. The following n lines describe the intervals. The (i+1)-th line of the input contains three integers ai, bi and ci separated by single spaces and such that 0 <= ai <= bi <= 50000 and 1 <= ci <= bi - ai+1.

Output

The output contains exactly one integer equal to the minimal size of set Z sharing at least ci elements with interval [ai, bi], for each i=1,2,...,n.

Sample Input

53 7 38 10 36 8 11 3 110 11 1

Sample Output

6

Source

Southwestern Europe 2002


题意:(转)

[ai, bi]区间内和点集Z至少有ci个共同元素,那也就是说如果我用Si表示区间[0,i]区间内至少有多少个元素的话,那么Sbi - Sai >= ci,这样我们就构造出来了一系列边,权值为ci,但是这远远不够,因为有很多点依然没有相连接起来(也就是从起点可能根本就还没有到终点的路线),此时,我们再看看Si的定义,也不难写出0<=Si - Si-1<=1的限制条件,虽然看上去是没有什么意义的条件,但是如果你也把它构造出一系列的边的话,这样从起点到终点的最短路也就顺理成章的出现了。

我们将上面的限制条件写为同意的形式:

Sbi - Sai >= ci

Si - Si-1 >= 0

Si-1 - Si >= -1

这样一来就构造出了三种权值的边,而最短路自然也就没问题了。

但要注意的是,由于查分约束系统里常常会有负权边,所以为了避免负权回路,往往用Bellman-Ford或是SPFA求解(存在负权回路则最短路不存在)。

PS:

因为求的是[ai,bi]区间,所以我们添加边的时候需要(u-1, v, w)!

把距离dis初始化为负无穷, if(dis[v] < dis[u] + w)即可!


POJ 和ZOJ用队列和栈都能过,但是HDU用栈会超时,只能用队列!

代码如下:(栈)

#include <cstdio>#include <cstring>#include <stack>#include <iostream>#include <algorithm>using namespace std;#define INF 0x3f3f3f3f#define N 50017#define M 50017int n, m, k;int Edgehead[N], dis[N];struct Edge{    int v,w,next;} Edge[3*M];bool vis[N];//int cont[N];int minn, maxx;int MIN(int a, int b){    if(a < b)        return a;    return b;}int MAX(int a, int b){    if(a > b)        return a;    return b;}void Addedge(int u, int v, int w){    Edge[k].next = Edgehead[u];    Edge[k].w = w;    Edge[k].v = v;    Edgehead[u] = k++;}int SPFA( int start)//stack{    int sta[N];    int top = 0;    //memset(cont,0,sizeof(cont);    for(int i = 1 ; i <= n ; i++ )        dis[i] = -INF;    dis[start] = 0;    //++cont[start];    memset(vis,false,sizeof(vis));    sta[++top] = start;    vis[start] = true;    while(top)    {        int u = sta[top--];        vis[u] = false;        for(int i = Edgehead[u]; i != -1; i = Edge[i].next)//注意        {            int v = Edge[i].v;            int w = Edge[i].w;            if(dis[v] < dis[u] + w)            {                dis[v] = dis[u]+w;                if( !vis[v] )//防止出现环                {                    sta[++top] = v;                    vis[v] = true;                }                //if(++cont[v] > n)//有负环                //return -1;            }        }    }    return dis[maxx];}int main(){    int u, v, w;    while(~scanf("%d",&n))//n为目的地    {        k = 1;        memset(Edgehead,-1,sizeof(Edgehead));        minn = INF;        maxx = -1;        for(int i = 1 ; i <= n ; i++ )        {            scanf("%d%d%d",&u,&v,&w);            Addedge(u-1,v,w);            maxx = MAX(v,maxx);            minn = MIN(u-1,minn);        }        for(int i = minn; i <= maxx; i++)//新边,保证图的连通性还必须添加每相邻两个整数点i,i+1的边        {            Addedge(i,i+1,0);            Addedge(i+1,i,-1);        }        int ans = SPFA(minn);//从点minn开始寻找最短路        printf("%d\n",ans);    }    return 0;}


HDU队列:

#include <cstdio>#include <cstring>#include <stack>#include <iostream>#include <algorithm>#include <queue>using namespace std;#define INF 0x3f3f3f3f#define N 50017#define M 50017int n, m, k;int Edgehead[N], dis[N];struct Edge{    int v,w,next;} Edge[3*M];bool vis[N];//int cont[N];int minn, maxx;int MIN(int a, int b){    if(a < b)        return a;    return b;}int MAX(int a, int b){    if(a > b)        return a;    return b;}void Addedge(int u, int v, int w){    Edge[k].next = Edgehead[u];    Edge[k].w = w;    Edge[k].v = v;    Edgehead[u] = k++;}int SPFA( int start)//stack{    queue<int>q;    //int sta[N];    //memset(cont,0,sizeof(cont);    int top = 0;    for(int i = minn ; i <= maxx ; i++ )        dis[i] = -INF;    dis[start] = 0;    //++cont[start];    memset(vis,false,sizeof(vis));    //sta[++top] = start;    q.push(start);    vis[start] = true;    while(!q.empty())    {        //int u = sta[top--];        int u = q.front();        q.pop();        vis[u] = false;        for(int i = Edgehead[u]; i != -1; i = Edge[i].next)//注意        {            int v = Edge[i].v;            int w = Edge[i].w;            if(dis[v] < dis[u] + w)            {                dis[v] = dis[u]+w;                if( !vis[v] )//防止出现环                {                    //sta[++top] = v;                    q.push(v);                    vis[v] = true;                }                //    if(++cont[v] > n)//有负环                //        return -1;            }        }    }    return dis[maxx];}int main(){    int u, v, w;    while(~scanf("%d",&n))//n为目的地    {        k = 1;        memset(Edgehead,-1,sizeof(Edgehead));        minn = INF;        maxx = -1;        for(int i = 1 ; i <= n ; i++ )        {            scanf("%d%d%d",&u,&v,&w);            Addedge(u-1,v,w);            maxx = MAX(v,maxx);            minn = MIN(u-1,minn);        }        for(int i = minn; i <= maxx; i++)//新边,保证图的连通性还必须添加每相邻两个整数点i,i+1的边        {            Addedge(i,i+1,0);            Addedge(i+1,i,-1);        }        int ans = SPFA(minn);//从点minn开始寻找最短路        printf("%d\n",ans);    }    return 0;}

1 0
原创粉丝点击