POJ 1364 淺談奇妙整數集合Z範圍內超級源轉化

這裏寫圖片描述
世界真的很大
本來這道題是一道大水題,但是有一個非常大的坑
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
*/

嗯,就是這樣

發佈了163 篇原創文章 · 獲贊 21 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章