poj 1364 King (差分约束)

这道题 学到了很多,有必要写一下

题意:对于一个序列数字序列S。给出(si, ni, 0, ki)。

      如果是(si,ni,gt,ki),意思就是存在约束条件S[si]+S[si+1]+...S[si+ni] > ki,

      如果是(si,ni,lt,ki),意思就是存在约束条件S[si]+S[si+1]+...S[si+ni] < ki  
      判断所给的约束条件有无解,即是否存在这么一个序列S,有解就输出lamentable kingdom,无解就输出successful conspiracy。

思路:将这些约束条件转化为差分约束,不妨设T[x] = S[1]+S[2]+....S[x],那么上面式子就可以转化为: 

     1. T[si+ni] - T[si-1] > ki          2. T[si+ni] - T[si-1] < ki  

     又差分约束系统的求解只能针对>=或<=,无法求解>的系统,还好ki是整数,可以很容易将<转化为<=  
     1. T[si-1] - T[si+ni] <= -ki - 1    2. T[si+ni] - T[si-1] <= ki - 1  

     ///这想法是 一位叫依然的人的,直接copy过来了

差分约束问题 如果没给出源点,就得自己设一个超级源点,把所有的点连起来 这道题还有一个注意的是,点的个数,不是n个,而是N+2个!!!

#include <stdio.h>
#include <string.h>
#define VM 150
#define EM 300
#define inf 0x3f3f3f3f
int head[VM],ep;
struct edge
{
    int v,w,next;
} e[EM];

void addedge (int cu,int cv,int cw)
{
    ep ++;
    e[ep].v = cv;
    e[ep].w = cw;
    e[ep].next = head[cu];
    head[cu] = ep;
}
int spfa (int n)
{
    int vis[VM],dis[VM],cnt[VM],queue[VM];
    for (int i = 0; i <= n; i ++)    //原来从1开始初始化wa了N遍
    {
        vis[i] = 0;
        cnt[i] = 0;
        dis[i] = inf;
    }
    dis[n+2] = 0;
    int front = 0,rear = 0;
    queue[rear++] = n+2;
    vis[n+2] = 1;
    cnt[n+2] = 1;
    while (front != rear)
    {
        int u = queue[front];
        front = (front+1)%(n+5);
        vis[u] = 0;
        for (int i = head[u]; i != -1; i = e[i].next)
        {
            int v = e[i].v;
            if (dis[v] > dis[u] + e[i].w)
            {
                dis[v] = dis[u] + e[i].w;
                if (!vis[v])
                {
                    vis[v] = 1;
                    cnt[v] ++;
                    if (cnt[v] > n+1)   //原来有N+1个点,外加一个超级源点 所以是入队列次数>=n+2才有负环
                        return 0;
                    queue[rear] = v;
                    rear = (rear+1)%(n+5);
                }
            }
        }
    }
    return 1;
}
int main ()
{
    int n,m,v1,l,cost;
    char c[4];
    while (1)
    {
        scanf ("%d",&n);
        if (n == 0)
            break;
        scanf ("%d",&m);
        memset (head,-1,sizeof(head));
        ep = 0;
        while (m --)
        {
            scanf ("%d%d%s%d",&v1,&l,c,&cost);
            if (c[0] == 'g')
                addedge (v1+l,v1-1,-1*cost-1);     //0<v1<= 100 所点点包含有0 其有n+1个点
            else
                addedge (v1-1,v1+l,cost - 1);
        }
        for (int i = 1; i <= n; i ++)
            addedge(n+2,i,0);
        int ans = spfa (n);
        if (ans == 0)
            printf ("successful conspiracy\n");
        else
            printf ("lamentable kingdom\n");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值