POJ 1364 浅谈奇妙整数集合Z范围内超级源转化

来源:互联网 发布:freebsd和ubuntu 编辑:程序博客网 时间:2024/06/03 18:20

这里写图片描述
世界真的很大
本来这道题是一道大水题,但是有一个非常大的坑
WA了数次,高人指点一项确实如此,细想一会儿才有种恍然大悟的感觉
差分约束不仅仅是模型转化的问题,建图时的细节问题也值得注意

看题先:

description:

一次,在一个王国,有一个女王,那个女王正在期待一个婴儿。女王祈祷:“如果我的孩子是一个儿子,只有他是一个健全的国王”,9个月后,她的孩子出生,确实生下了一个漂亮的儿子。
不幸的是,正如以前在皇室中发生的那样,儿子有点迟钝。经过多年的学习,他只能添加整数,并比较结果是否大于或小于给定的整数。此外,这些数字必须以序列的形式写出来,并且只能顺序排列连续的子序列。

老王对他的儿子非常不满。但他准备做一切事情,让他的儿子在死后统治王国。关于他的儿子的技能,他决定国王必须决定的每一个问题都必须以一个有限的整数序列的形式呈现,并且通过说明一个整数约束来完成这个决定极限)为该序列的总和。这样,至少有一些希望,他的儿子能做出一些决定。

老王死后,年轻的国王开始统治。但很快,很多人对他的决定感到非常不满,并决定取消他。他们试图通过证明他的决定是错误的。

因此,一些阴谋者向年轻的国王提出了他必须决定的一系列问题。一组问题是序列S = {a1,a2,…,an}的子序列Si = {aSi,aSi + 1,…,aSi + ni}的形式。国王想了一会儿,然后决定,即他设定每个子序列Si的和aSi + aSi + 1 + … + aSi + ni为整数约束ki(即aSi + aSi + 1 + … + aSi + ni

input:

The input consists of blocks of lines. Each block except the last corresponds to one set of problems and king’s decisions about them. In the first line of the block there are integers n, and m where 0 < n <= 100 is length of the sequence S and 0 < m <= 100 is the number of subsequences Si. Next m lines contain particular decisions coded in the form of quadruples si, ni, oi, ki, where oi represents operator > (coded as gt) or operator < (coded as lt) respectively. The symbols si, ni and ki have the meaning described above. The last block consists of just one line containing 0.

output:

The output contains the lines corresponding to the blocks in the input. A line contains text successful conspiracy when such a sequence does not exist. Otherwise it contains text lamentable kingdom. There is no line in the output corresponding to the last “null” block of the input.

这道题,就是说给出一些条件限制,问满足所有条件的序列存在不存在
每一个条件是指一段序列大于或小于某个给定值。
处理成前缀和的方式的话,就变成了一堆不等式会不会矛盾这样一个问题,显然的差分约束

每个大于条件处理成前缀和相减:
SUM(v) - SUM(u) >= K+1 ==> SUM(v) >= SUM(u) +K + 1
每个小于条件也如下处理:
SUM(v) - SUM(u) <= K-1 ==> SUM(u) >= SUM(v) - K + 1

然后很显然的最长路
虚拟一个超级原点,为0,与所有点连一条边权为0的边

A了?
WA了
看似完美的思路其实有一点小瑕疵
比如说“虚拟一个超级原点,为0,与所有点连一条边权为0的边”
这句

在这道题里面,0点代表什么呢?代表前缀和为0的点,其向任意一个点连边,表示那个点对应的前缀和大于等于边权
我们个每个点连了一条边权为0的边,意思是每一个前缀和都大于等于0
那么问题来了,谁说的?
这道题的序列,可以有负数。。。
那我们的连边就出现问题了,我们的连边限定了每一个前缀和都是正数,但是实则不然,题目中并没有给出这样的条件,所以原点连的边权不能为0

考虑到既然没有限制,那就连一条负无穷的边就好了
由于为了方便更新,就连一条负无穷+10的边就好

确实有点坑
做题不要更具自己的习惯来,还是要老老实实的分析才好

完整代码:

#include<stdio.h>#include<queue>#include<cstring>#include<algorithm>using namespace std;const int INF=0x3f3f3f3f;struct edge{    int v,w,last;}ed[4000010];priority_queue <pair<int,int> > state ;int n,m,num=0,S=0;int head[200010],dis[200010],se[200010],book[200010];char ss[110];void add(int u,int v,int w){    num++;    ed[num].w=w;    ed[num].v=v;    ed[num].last=head[u];    head[u]=num;}bool SPFA(){    memset(book,0,sizeof(book));    memset(se,0,sizeof(se));    while(!state.empty()) state.pop();    for(int i=1;i<=n+1;i++) dis[i]=-INF;    dis[S]=0,se[S]=1;    state.push(make_pair(dis[S],S));    while(!state.empty())    {        int u=state.top().second;        se[u]=0,state.pop();        for(int i=head[u];i;i=ed[i].last)        {            int v=ed[i].v;            if(dis[v]<dis[u]+ed[i].w)            {                dis[v]=dis[u]+ed[i].w;                if(!se[v]) book[v]++,se[v]=1,state.push(make_pair(dis[v],v));                if(book[v]>n) return false ;            }        }    }    return true ;}void init(){    memset(head,0,sizeof(head));    num=0;}int main(){    while(1)    {        init();        scanf("%d",&n);        if(!n) break ;        scanf("%d",&m);        while(m--)        {            int u,v,w;            scanf("%d%d",&u,&v);            scanf("%s",ss);            scanf("%d",&w);            if(ss[0]=='g') add(u-1,u+v,w+1);            else add(u+v,u-1,-w+1);        }        for(int i=1;i<=n;i++) add(S,i,-INF+10);        if(!SPFA()) printf("successful conspiracy\n");        else printf("lamentable kingdom\n");    }    return 0;}/*EL PSY CONGROO*/

嗯,就是这样

原创粉丝点击