UVA 515 差分约束 SPFA判负

第一次看这个题目,完全不知道怎么做,看起来又像是可以建个图进行搜索,但题目条件就给了你几个不等式,这是怎么个做法。。。之后google了下才知道还有个差分约束这样的东西,能够把不等式化成图,要求某个点在满足所有不等式的情况下的最大取值,只需对建好的图进行一次最短路即可

不过要使得a b 点满足这样 a<=b+k这种不等式,还得对题目所给的不等式进行下改装

原不等式无非就是 输入个 si ni,使得存在 A(si)+...A(si+ni)<k 或者 >k,我们新定义一个s[],s[i]代表从1 到 i的所有的点的和,这样,原不等式就会变成 s[si+ni]-s[si-1]>=k+1  或者 小于=k-1,进行下移项,即可变成差分约束不等式的形式,这样每个点的含义就是 对应的s[i]。

此外注意添加一个超级原点 N+1,跟所有点进行下连通,保证图的连通性。

其实题目还有个难点就是,他求是否能满足着m个不等式,如果不满足,意味着有相互冲突的不等式,也就是某个点值既可能正也可能负,也就是说图上存在负环。。。。这个转换确实比较难推敲,尤其是像我这种对图论题目还只是入门的菜鸟。

因此,建好图后,只需用SPFA遍历一下,判断有无负环即可。

此外,还有个疑惑,就是差分约束一定要有等于吗?就像上面的式子,如果不是为了满足=的条件,就不必用k+1和k-1来代替原来的k了。。。这个还有待考证

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define N 250
using namespace std;
int u[N],v[N],w[N],nt[N],ft[N/2],d[N/2],num[N/2],vis[N/2];
int n,m,cnt,flag;
void addedge(int a,int b,int c)
{
    u[cnt]=a;
    v[cnt]=b;
    w[cnt]=c;
    nt[cnt]=ft[a];
    ft[a]=cnt++;
}
void spfa()
{
    int i,j;
    for (i=0;i<=n;i++)
        d[i]=1<<30;
    memset(num,0,sizeof num);
    memset(vis,0,sizeof vis);
    flag=1;
    d[n+1]=0;
    queue <int> q;
    q.push(n+1);
    vis[n+1]=1;
    while (!q.empty())
    {
        int x=q.front();
        q.pop();
        vis[x]=0;
        num[x]++;
        if (num[x]>n)
        {
            flag=0;
            return;
        }
        for (i=ft[x];i>=0;i=nt[i])
        {
            int nx=v[i];
            if (d[nx]>d[x]+w[i])
            {
                d[nx]=d[x]+w[i];
                if (!vis[nx])
                {
                    q.push(nx);
                    vis[nx]=1;
                }
            }
        }
    }

}
int main()
{
    int i,j;
    char ch[3];
    while (scanf("%d",&n))
    {
        if (!n) break;
        cnt=0;
        scanf("%d",&m);
        int a,b,k,si,ni;
        memset(ft,-1,sizeof ft);
        for (i=1;i<=m;i++)
        {
            scanf("%d%d%s%d",&si,&ni,ch,&k);
            if (ch[0]=='g')
            {
                addedge(si+ni,si-1,(-k-1));//用差分约束不等式建图,下同
            }
            else
            {
                addedge(si-1,si+ni,k-1);
            }
        }
        for (i=1;i<=n;i++) //将n+1作为超级原点进行连通。
            addedge(n+1,i,0);
        spfa();
        if (flag)
        {
            puts("lamentable kingdom");

        }
        else puts("successful conspiracy");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/kkrisen/p/3518860.html