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\n");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\n");
else printf("%d\n",dis[n]);
return 0;
}