Luogu_P4878 [USACO05DEC] 布局 差分约束(不连通)

Luogu_P4878 [USACO05DEC] 布局

差分约束(不连通)


题目链接
又是差分约束
但是这次并没有联通的性质
题目疯狂暗示
无穷远的情况就是互相不连通
那么只好找一个超级源点(0)
(0)和所有的点连一条边权为(0)的边
这样的话从(0)跑spfa就可以知道各自的连通块里有没有负环
然后再从(1)跑看是不是能更新到(n)
假如不能就是(-2)
能就是(dis[n])


代码如下:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
int n,l,d,head[maxn*maxn],tot;
struct node{
    int nxt,dis,to;
    #define nxt(x) e[x].nxt
    #define dis(x) e[x].dis
    #define to(x) e[x].to
}e[maxn*maxn];
inline void add(int from,int to,int w){
    to(++tot)=to;dis(tot)=w;
    nxt(tot)=head[from];head[from]=tot;
}
int dis[maxn],inq[maxn],cnt[maxn];
inline void spfa(int st){
    queue<int> q;memset(dis,0x3f,sizeof(dis));memset(cnt,0,sizeof(cnt));memset(inq,0,sizeof(inq));
    q.push(st);dis[st]=0;cnt[st]=1;inq[st]=1;
    while(q.size()){
        int x=q.front();q.pop();inq[x]=0;
        for(int i=head[x];i;i=nxt(i)){
            int y=to(i);
            if(dis[y]>dis[x]+dis(i)){
                dis[y]=dis[x]+dis(i);
                cnt[y]=cnt[x]+1;
                if(cnt[y]>n){
                    printf("-1
");exit(0);
                }
                if(inq[y]) continue;
                q.push(y);inq[y]=1;
            }
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&l,&d);
    for(int x,y,z,i=1;i<=l;i++) scanf("%d%d%d",&x,&y,&z),add(x,y,z);
    for(int x,y,z,i=1;i<=d;i++) scanf("%d%d%d",&x,&y,&z),add(y,x,-z);
    for(int i=1;i<=n;i++) add(0,i,0);
    spfa(0);
    spfa(1);
    if(dis[n]==0x3f3f3f3f) printf("-2
");
    else printf("%d
",dis[n]);
    return 0;
}
原文地址:https://www.cnblogs.com/ChrisKKK/p/11643917.html