POJ 1364[King]题解

(传送门)

题目大意

给出e种大小关系,每种关系都可以用a[i]+a[i+1]+……+a[i+j] >(或 < )一个定值(i+j<=n),问这n种关系是否存在互相矛盾的情况。

解题分析

这道题是典型的差分约束系统。
差分约束系统解决这样一类题,给出n个不等式xi-yi<=zi,要求求出给定数的最大值。首先联想一下spfa。
是不是有dst[v] <= dst[u]+w[j];

等一下,对转移方程中的判断式进行一些小小的改变 dst[v]-dst[u] <= w[j]
这样的话就与xi-yi<=zi等价了(格式相同)
所以可以将差分约束系统转换成spfa或其他最短路算法处理,每次xi-yi<=zi,可以处理成从yi到xi建一条边权为zi的边,然后用spfa刷最短路(dij也可以,但是注意不能有负边权)。所以差分约束系统的核心就这样,关键就是建模的问题。

如果是>=,可以转换成<=,也可以不变,改成求最小值,刷最长路。

回到这道题,由于a[i]+a[i+1]+……a[i+j]是一段连续的区间,所以可以考虑用前缀和来解决,a[i]+a[i+1]+……+a[i+j]<=k转换成s[i+j]-s[i-1]<=k,这样就可以转换成差分约束系统,剩下来就比较明显,判断spfa是否存在负环,判断负环比较容易;但还有几个小细节,一是注意建起来的图并不一定是联通的,解决方案有两个,一个是建一个超级源,跟每个点都连一条边权为0的边,另一个是把所有点都加入队列内,vs打成真,初始dst打成0,第二是一共有n+1个点,不要把0号点漏掉,第三是这道题>=或<=都可以,但是一定要全部转换成一种类型。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,e,INF,tot,ans,son[105],nxt[105],lnk[105],w[105],que[105],num[105],dst[105];
bool vs[105];
inline void readi(int &x)
{
    x=0; int f=1; char ch=getchar();
    while ('0'>ch||ch>'9') {if (ch=='-') f=-f; ch=getchar();}
    while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    x*=f;
}
void _add(int x,int y,int z)
{
    tot++;
    son[tot]=y; w[tot]=z; nxt[tot]=lnk[x]; lnk[x]=tot;
}
void _init()
{
    readi(e); tot=0;
    memset(nxt,0,sizeof(nxt));
    memset(lnk,0,sizeof(lnk));
    for (int i=1;i<=e;i++)
    {
        int x,y,z; readi(x); readi(y);
        char ch=getchar(); while (ch!='g'&&ch!='l') ch=getchar();
        readi(z);
        if (ch=='l') _add(x-1,x+y,z-1);
        else _add(x+y,x-1,-z-1);
    }
}
bool spfa()
{
    memset(vs,1,sizeof(vs));
    memset(num,0,sizeof(num));
    memset(dst,0,sizeof(dst));
    int hed=0,til=n+1;
    for (int i=0;i<=n;i++) que[i+1]=i;
    while (hed!=til)
    {
        hed=(hed+1)%105;
        vs[que[hed]]=false;
        for (int j=lnk[que[hed]];j;j=nxt[j])
            if (dst[son[j]]>dst[que[hed]]+w[j])
            {
                dst[son[j]]=dst[que[hed]]+w[j];
                if (!vs[son[j]]){
                    til=(til+1)%105;
                    que[til]=son[j];
                    vs[son[j]]=true;
                    num[son[j]]++;
                    if (num[son[j]]>=n) return false;
                    if (dst[son[j]]<dst[que[(hed+1)%105]]) swap(que[til],que[(hed+1)%105]);
                }
            }
    }
    return true;
}
void _solve()
{
    if (spfa()) printf("lamentable kingdom\n");
    else printf("successful conspiracy\n");
}
int main()
{
    readi(n);
    while (n)
    {
        _init();
        _solve();
        readi(n);
    }
    return 0;
}

PS:
本博客过于简陋,望各位神犇能谅解,如有错误,请多指出,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值