poj 1201 (差分约束系统)

来源:互联网 发布:java工作经验的描述 编辑:程序博客网 时间:2024/06/03 15:05

      题意:给你n条线段,形如a b c,代表起点,终点以及最少从线段上取多少个点,问你在满足所有约束条件下最多能从所有线段上取多少个点。

      分析:为了构造约束条件,首先想象有一个源点,d[x]就表示从源点到x点这个范围内取的点数,于是对每一条线段a b c,有d[b]-d[a]>=c,但后来发现这样不行,例如有1 3 3,3 5 2,按前面的构造方法求出来的解是5,但正确的解应该是4,因为线段在3点处重叠了。为了解决这个问题,可将每条线段的区间构造为左闭右开区间,即[a,b+1),而且这样仍满足题意。但只这样的话约束条件还不够,构建的图不连通,于是还要寻找其它的约束条件。其实确实有点不好想,我也是看网上大神讲了后才知道的,题目中隐含的约束条件:在区间[i,i+1)内,最少取0个点,最多取1个点,即0<=d[i+1]-d[i]<=1,于是得到以下全部约束条件:

d[b+1]-d[a]>=c;

d[i]-d[i+1]>=-1;

d[i+1]-d[i]>=0;

      另外,读输入时,记录下出现的点里面的最小点min和最大点max,源点就设为min点。

      接下来建图求最长路就行了。输出d[max]即为解。

代码如下:

     

#include <cstdio>#include <stack>#include <set>#include <iostream>#include <string>#include <vector>#include <queue>#include <functional>#include <cstring>#include <algorithm>#include <cctype>#include <string>#include <map>#include <iomanip>#include <cmath>#define LL long long#define ULL unsigned long long#define SZ(x) (int)x.size()#define Lowbit(x) ((x) & (-x))#define MP(a, b) make_pair(a, b)#define MS(arr, num) memset(arr, num, sizeof(arr))#define PB push_back#define F first#define S second#define ROP freopen("input.txt", "r", stdin);#define MID(a, b) (a + ((b - a) >> 1))#define LC rt << 1, l, mid#define RC rt << 1|1, mid + 1, r#define LRT rt << 1#define RRT rt << 1|1#define BitCount(x) __builtin_popcount(x)#define BitCountll(x) __builtin_popcountll(x)#define LeftPos(x) 32 - __builtin_clz(x) - 1#define LeftPosll(x) 64 - __builtin_clzll(x) - 1const double PI = acos(-1.0);const int INF = 0x3f3f3f3f;using namespace std;const double eps = 1e-8;const int MAXN = 300 + 10;const int MOD = 1000007;const int M=20010;const int N=1000010;const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };typedef pair<int, int> pii;int n,m,minn,maxx,d[N],q[N];int e,w[N],u[N],v[N],first[N],next[N];bool vis[N];void add(int a,int b,int c){    u[e]=a; v[e]=b; w[e]=c;    next[e]=first[a];    first[a]=e++;}void build(){    int i,j,a,b,c;    e=0;    minn=INF; maxx=-INF;    MS(first,-1);    for (i=0;i<n;i++) {        scanf("%d%d%d",&a,&b,&c);        minn=min(a,minn);        maxx=max(b+1,maxx);        add(a,b+1,c);    }    for (i=minn;i<maxx;i++){        add(i,i+1,0);        add(i+1,i,-1);    }}int spfa(){    int i,j;    int right,left;    int t;    right=left=0;    MS(vis,false);    for (i=minn;i<=maxx;d[i++]=-INF);    d[minn]=0;    q[right++]=minn;    while(left<right)    {        t=q[left++];        vis[t]=false;        for (i=first[t];i!=-1;i=next[i]){            if (d[v[i]]<d[u[i]]+w[i]){                d[v[i]]=d[u[i]]+w[i];                if (!vis[v[i]]){                    q[right++]=v[i];                    vis[v[i]]=true;                }            }        }    }    //for (i=minn;i<=maxx;cout<<d[i++]<<" "); cout<<endl;    return d[maxx];}int main(){    int i,j;    while(~scanf("%d",&n))    {        build(); int t=spfa();        printf("%d\n",t);    }}

     这题也可以通过求最短路解决,但是要注意以max为源点来求,输出-d[min]为解(其实我也不明白为什么要这样)。      

代码如下:

#include <cstdio>#include <stack>#include <set>#include <iostream>#include <string>#include <vector>#include <queue>#include <functional>#include <cstring>#include <algorithm>#include <cctype>#include <string>#include <map>#include <iomanip>#include <cmath>#define LL long long#define ULL unsigned long long#define SZ(x) (int)x.size()#define Lowbit(x) ((x) & (-x))#define MP(a, b) make_pair(a, b)#define MS(arr, num) memset(arr, num, sizeof(arr))#define PB push_back#define F first#define S second#define ROP freopen("input.txt", "r", stdin);#define MID(a, b) (a + ((b - a) >> 1))#define LC rt << 1, l, mid#define RC rt << 1|1, mid + 1, r#define LRT rt << 1#define RRT rt << 1|1#define BitCount(x) __builtin_popcount(x)#define BitCountll(x) __builtin_popcountll(x)#define LeftPos(x) 32 - __builtin_clz(x) - 1#define LeftPosll(x) 64 - __builtin_clzll(x) - 1const double PI = acos(-1.0);const int INF = 0x3f3f3f3f;using namespace std;const double eps = 1e-8;const int MAXN = 300 + 10;const int MOD = 1000007;const int M=20010;const int N=1000010;const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };typedef pair<int, int> pii;int n,m,minn,maxx,d[N];int e,w[N],u[N],v[N],first[N],next[N];bool vis[N];void add(int a,int b,int c){    u[e]=a; v[e]=b; w[e]=c;    next[e]=first[a];    first[a]=e++;}void build(){    int i,j,a,b,c;    e=0;    minn=INF; maxx=-INF;    MS(first,-1);    for (i=0;i<n;i++) {        scanf("%d%d%d",&a,&b,&c);        minn=min(a,minn);        maxx=max(b+1,maxx);        add(b+1,a,-c);    }    for (i=minn;i<maxx;i++){        add(i,i+1,1);        add(i+1,i,0);    }}int spfa(){    int i,j;    int right,left;    int t, q[N];    right=left=0;    MS(vis,false);    for (i=minn;i<=maxx;d[i++]=INF);    d[maxx]=0;    q[right++]=maxx;    while(left<right)    {        t=q[left++];        vis[t]=false;        for (i=first[t];i!=-1;i=next[i]){            if (d[v[i]]>d[u[i]]+w[i]){                d[v[i]]=d[u[i]]+w[i];                if (!vis[v[i]]){                    q[right++]=v[i];                    vis[v[i]]=true;                }            }        }    }    //for (i=minn;i<=maxx;cout<<d[i++]<<" "); cout<<endl;    return -d[minn];}int main(){    int i,j;    while(~scanf("%d",&n))    {        build();        printf("%d\n",spfa());    }}





0 0
原创粉丝点击