poj1364 King

1 篇文章 0 订阅

http://poj.org/problem?id=1364 这题题目比较晦涩难懂,我是直接去看的网上的解释。是道差分约束的题,题目大意是这样:有一个序列S={a1,a2,a3,....,am},现在给出一些不等式

使得ai+a(i+1)+a(i+2)+.......+a(i+ni)>ki或者ai+a(i+1)+a(i+2)+.......+a(i+ni)<k。(注意这里是从ai本身开始后面再加ni个数),让你判断是否所有的不等式都满足条件,满足就输出

lamentable kingdom,不满足就输出successful conspiracy。(注意不要输反了,一开始我就是输反了 ,导致一直在查自己SPFA的错。。。)
由于差分约束只能解决同时大于等于或者同时小于等于的情况,所以我们需要对题给不等式做一些变形。

1).形如 ai ni gt ki 这种形式的 表示ai+a(i+1)+a(i+2)+.......+a(i+ni)>ki ,我们令Si 表示序列前i项的和 ,则前面不等式等价于 :

S(i+ni)-S(i-1)>ki <=> S(i-1)-S(i+ni)<=-ki -1;

2). 对 ai ni lt ki  一样的道理,转化为S(i+ni)-S(i-1)<ki  <=> S(i+ni)-S(i-1)<=ki-1;

这就是所有的通式,最后根据差分约束建立有向图:

gt: 建立有向边:(i+ni) -> (i-1)  权值为:-ki-1

lt :建立有向边: (i-1) -> (i+ni) 权值为:ki-1

最后判断是否所有不等式成立的条件就是是否有负环产生。直接用Bellman_ford或者spfa都行,接下来的就跟poj2983的处理一样了。下面是AC的代码:

再这里抱怨一句,不知道为什么,这题我用添加超源点的方式一直WA,改用下面这种方式才A了,但是把相同的添加源点的代码写到poj2983(http://blog.csdn.net/lyx35405/article/details/10053309)里面竟然能过。。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
#define inf 999999999
#define maxn 1003*10
struct node
{
    int y,w,next;
}edge[maxn];
queue<int> que;

int n,num,m;
int first[maxn],dis[maxn],fnum[maxn];
bool visit[maxn];
void initGraph(int x,int y,int w)
{
    edge[++num].y=y;edge[num].w=w;
    edge[num].next=first[x];
    first[x]=num;//相当于链表的头插入法,顶点x的所有边为一个邻接表
}

bool SPFA()
{
    memset(visit,1,sizeof(visit));
    memset(fnum,0,sizeof(fnum));
    memset(dis,0,sizeof(dis));
    for(int i=0;i<=n;i++) que.push(i);
    //visit[n+1]=1;
    while(!que.empty())
    {
        int x=que.front();
        que.pop();
        visit[x]=0;
        for(int i=first[x];i!=0;i=edge[i].next)
        {
            int y=edge[i].y;
            if(dis[x]+edge[i].w<dis[y])
            {
                dis[y]=dis[x]+edge[i].w;
                if(!visit[y])
                {
                    visit[y]=1;
                    if(++fnum[y]>n) return 0;//无解
                    //printf("fnum[%d]=%d\n",y,fnum[y] );
                    que.push(y);
                }
            }
        }
    }
    return 1 ;//有解
}
int main()
{
    int si,ni,ki;
    char op[5];
    while(scanf("%d",&n)==1&&n)
    {
        scanf("%d",&m);
        num=0;
        memset(first,0,sizeof(first));
        while(m--)
        {
            scanf("%d%d%s%d",&si,&ni,op,&ki);
            if(op[0]=='g')
                initGraph(si+ni,si-1,-ki-1);
            else
                initGraph(si-1,si+ni,ki-1);
        }
        if(!SPFA()) printf("successful conspiracy\n");
        else printf("lamentable kingdom\n");
    }   
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值