POJ

来源:互联网 发布:快消品行业数据 编辑:程序博客网 时间:2024/06/08 00:27

题意
给你一个序列,S={a1,a2,……an},然后给你一些信息,判断是否存在解满足题目给的一些不等式的条件。gt表示>,lt表示<(注意是大于和小于,不是大于等于和小于等于).
比如题目给出的例子
4 2 (4个元素,2个不等式条件)
1 2 gt 0 表示a1+a2+a3>0,
2 2 lt 2 表示 a2+a3+a4<2,
首先题目给出的不等式是小于,但是差分约束系统只能处理小于等于的情况,所以要转化成小于等于的进行处理。对于整数处理方法非常简单直接减1…(来自dalao的说法,当初我以为只要是不等式的条件就可以差分约束了,结果差分约束系统的适用范围是处理大于等于,小于等于的情况)。
设s[i]为数组的前缀和。
大于的情况为
s[u+v]-s[u-1]>k;
那么我们可以转化为s[u-1]-s[u+v]

//全部放进队列的写法#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>#include<queue>using namespace std;#define INF 0x3f3f3f3fconst int MAXN=1e2+7;const int MAXM=1e2*3+7;struct node{    int to,next,w;//其中edge[i].to表示第i条边的终点,edge[i].next表示与第i条边同起点的下一条边的存储位置,edge[i].w为边权值.}Edge[MAXM];//Edge保持m条边的个数 int head[MAXM];int dis[MAXN];int num[MAXN];bool vis[MAXN];int n,m,tot;//head和dis保持n个点 void add_edge(int a,int b,int c){    Edge[++tot].to=b;    Edge[tot].w=c;    Edge[tot].next=head[a];    head[a]=tot;}             int SPFA(int s){    queue<int>q;    int k,to,w;    memset(num,0,sizeof(num));    memset(vis,false,sizeof(vis));//首先这个题的 Si...sn我的写法会从0开始的....所以如果用超级源点..不能用0点(WA了一个小时看了别人的说法才知道是多么痛的领悟)..所以我干脆就没用超级点...学别人直接开始的时候把所有点入队~~效果是一样的        for(int i=0;i<=n;i++)    {        dis[i]=0;        num[i]=0;//ORZ这里如果num[i]=1的话,UVA就WA,改成0就过了         vis[i]=true;        q.push(i);    } //为什么不像之前那样写,因为这道题涉及0点(超级源点要与题目给的任何点或者范围无关才可以,不然会影响结果),//所以我们换种写法,直接把所有点都放进去队列,dis大小也是0(表示超级源点到任何点的距离都为0)。这样就可以得出答案了。      while(!q.empty())    {        k=q.front();        q.pop();        vis[k]=0;//弹出队列并取消标记        for(int i=head[k];i!=-1;i=Edge[i].next)        {            to=Edge[i].to;            w=Edge[i].w;            if(dis[k]+w<dis[to])            {                dis[to]=dis[k]+w;                if(!vis[to])//判断这个点是否在队列里面,如果不在加入队列                 {                    vis[to]=true;                    q.push(to);                    num[to]++;                    if(num[to]>n)//判断是否成环                     return -1;                }            }        }    }    return 1;}int main(){    while(~scanf("%d",&n),n)    {        scanf("%d",&m);        memset(head,-1,sizeof(head));        tot=1;        for(int i=1;i<=m;i++)        {            char c[5];            int u,v,w;            scanf("%d%d%s%d",&u,&v,c,&w);            if(c[0]=='g')//大于             add_edge(v+u,u-1,-w-1);            else//小于             add_edge(u-1,v+u,w-1);        }         int ans=SPFA(0);        if(ans==-1)         printf("successful conspiracy\n");        else        printf("lamentable kingdom\n");    }    return 0;}//首先题目给出的不等式是小于,但是差分约束系统只能处理小于等于的情况,所以要转化成小于等于的进行处理。对于整数处理方法非常简单= =//如果题目给的是<,>而不是<=,>=的话,就将<,>变成<=,>=.比如A-B<1变成A-B<=0. 
//n+1作为超级源点的写法#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>#include<queue>using namespace std;#define INF 0x3f3f3f3fconst int MAXN=1e2+7;const int MAXM=1e2*3+7;struct node{    int to,next,w;//其中edge[i].to表示第i条边的终点,edge[i].next表示与第i条边同起点的下一条边的存储位置,edge[i].w为边权值.}Edge[MAXM];//Edge保持m条边的个数 int head[MAXM];int dis[MAXN];int num[MAXN];bool vis[MAXN];int n,m,tot;//head和dis保持n个点 void add_edge(int a,int b,int c){    Edge[++tot].to=b;    Edge[tot].w=c;    Edge[tot].next=head[a];    head[a]=tot;}             int SPFA(int s){    queue<int>q;    int k,to,w;    memset(num,0,sizeof(num));    memset(vis,false,sizeof(vis));    for(int i=0;i<=n;i++)    dis[i]=INF;    dis[s]=0;    vis[s]=true;    q.push(s);    while(!q.empty())    {        k=q.front();        q.pop();        vis[k]=false;//弹出队列并取消标记        for(int i=head[k];i!=-1;i=Edge[i].next)        {            to=Edge[i].to;            w=Edge[i].w;            if(dis[k]+w<dis[to])            {                dis[to]=dis[k]+w;                if(!vis[to])//判断这个点是否在队列里面,如果不在加入队列                 {                    vis[to]=true;                    q.push(to);                    num[to]++;                    if(num[to]>n)//判断是否成环                     return -1;                }            }        }    }    return 1;}int main(){    while(~scanf("%d",&n),n)    {        scanf("%d",&m);        memset(head,-1,sizeof(head));        tot=1;        for(int i=1;i<=n;i++)        add_edge(n+1,i,0);        for(int i=1;i<=m;i++)        {            char c[5];            int u,v,w;            scanf("%d%d%s%d",&u,&v,c,&w);            if(c[0]=='g')//大于             add_edge(v+u,u-1,-w-1);            //如果用add_edge(v+u,u-1,-w-1)的话会错的,因为用SPFA要用超级源点保证图的连通性,但是(注意了)(v+u,u-1,-w-1)说明会出现0,            //而你用0作为源点,就会影响结果。所以只能是(v+u+1,u,-w-1)             else//小于             add_edge(u-1,v+u,w-1);        }         int ans=SPFA(n+1);        if(ans==-1)         printf("successful conspiracy\n");        else        printf("lamentable kingdom\n");    }    return 0;}//首先题目给出的不等式是小于,但是差分约束系统只能处理小于等于的情况,所以要转化成小于等于的进行处理。对于整数处理方法非常简单= =//如果题目给的是<,>而不是<=,>=的话,就将<,>变成<=,>=.比如A-B<1变成A-B<=0. 
//可以用0作为超级源点的写法#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>#include<queue>using namespace std;#define INF 0x3f3f3f3fconst int MAXN=1e2+7;const int MAXM=1e2*3+7;struct node{    int to,next,w;//其中edge[i].to表示第i条边的终点,edge[i].next表示与第i条边同起点的下一条边的存储位置,edge[i].w为边权值.}Edge[MAXM];//Edge保持m条边的个数 int head[MAXM];int dis[MAXN];int num[MAXN];bool vis[MAXN];int n,m,tot;//head和dis保持n个点 void add_edge(int a,int b,int c){    Edge[++tot].to=b;    Edge[tot].w=c;    Edge[tot].next=head[a];    head[a]=tot;}             int SPFA(int s){    queue<int>q;    int k,to,w;    memset(num,0,sizeof(num));    memset(vis,false,sizeof(vis));    for(int i=0;i<=n+1;i++)//因为是(v+u+1,u,-w-1),所以n要加1.     dis[i]=INF;    dis[s]=0;    vis[s]=true;    q.push(s);    while(!q.empty())    {        k=q.front();        q.pop();        vis[k]=false;//弹出队列并取消标记        for(int i=head[k];i!=-1;i=Edge[i].next)        {            to=Edge[i].to;            w=Edge[i].w;            if(dis[k]+w<dis[to])            {                dis[to]=dis[k]+w;                if(!vis[to])//判断这个点是否在队列里面,如果不在加入队列                 {                    vis[to]=true;                    q.push(to);                    num[to]++;                    if(num[to]>n)//判断是否成环                     return -1;                }            }        }    }    return 1;}int main(){    while(~scanf("%d",&n),n)    {        scanf("%d",&m);        memset(head,-1,sizeof(head));        tot=1;        for(int i=1;i<=n;i++)        add_edge(0,i,0);        for(int i=1;i<=m;i++)        {            char c[5];            int u,v,w;            scanf("%d%d%s%d",&u,&v,c,&w);            if(c[0]=='g')//大于             add_edge(v+u+1,u,-w-1);            //如果用add_edge(v+u,u-1,-w-1)的话会错的,因为用SPFA要用超级源点保证图的连通性,但是(注意了)(v+u,u-1,-w-1)说明会出现0,            //而你用0作为源点,就会影响结果。所以只能是(v+u+1,u,-w-1)             else//小于             add_edge(u,v+u+1,w-1);        }         int ans=SPFA(0);        if(ans==-1)         printf("successful conspiracy\n");        else        printf("lamentable kingdom\n");    }    return 0;}//首先题目给出的不等式是小于,但是差分约束系统只能处理小于等于的情况,所以要转化成小于等于的进行处理。对于整数处理方法非常简单= =//如果题目给的是<,>而不是<=,>=的话,就将<,>变成<=,>=.比如A-B<1变成A-B<=0. 
原创粉丝点击