bzoj 1731 Layout 排队布局 —— 差分约束

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1731

差分约束;

ML: dis[y] - dis[x] <= k,即 x 向 y 连边权为 k 的边;

MD: dis[y] - dis[x] >= k,即 y 向 x 连边权为 -k 的边;

有负环说明要 <= 的 k 无限小,所以无解,输出 -1;

走不到说明 1 与 n 之间无限制关系,所以 dis[n] 可以无限大,输出 -2;

还要注意隐藏条件是编号小的在编号大的前面,所以还有 dis[x-1] <= dis[x];

注意 spfa 判负环那里是松弛次数不超过 n 而不是入队次数(入队次数也可以?总之WA了...)。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
int const xn=1005,xm=20005+xn;//!!!
int n,ml,md,hd[xn],ct,to[xm],nxt[xm],w[xm],cnt[xn];
ll dis[xn];
bool vis[xn];
queue<int>q;
void add(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; w[ct]=z; hd[x]=ct;}
int rd()
{
    int ret=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
    while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
    return f?ret:-ret;
}
ll spfa()
{
    memset(dis,0x3f,sizeof dis); ll inf=dis[1];//ll
    dis[1]=0; q.push(1); cnt[1]=1; vis[1]=1; 
    while(q.size())
    {
        int x=q.front(); q.pop(); vis[x]=0;
        for(int i=hd[x],u;i;i=nxt[i])
            if(dis[u=to[i]]>dis[x]+w[i])
            {
                dis[u]=dis[x]+w[i];
                if(!vis[u])vis[u]=1,q.push(u);
                cnt[u]++;//不一定入队
                if(cnt[u]>=n)return -1;
            }
    }
    if(dis[n]==inf)return -2;
    return dis[n];
}
int main()
{
    n=rd(); ml=rd(); md=rd();
    for(int i=1,x,y,z;i<=ml;i++)
    {
        x=rd(); y=rd(); z=rd();
        add(x,y,z);
    }
    for(int i=1,x,y,z;i<=md;i++)
    {
        x=rd(); y=rd(); z=rd();
        add(y,x,-z);
    }
    for(int x=2;x<=n;x++)add(x,x-1,0);
    printf("%lld\n",spfa());
    return 0;
}

 

posted @ 2018-09-26 09:57  Zinn  阅读(229)  评论(0编辑  收藏  举报