1. 程式人生 > >BZOJ 2330: [SCOI2011]糖果【差分約束】

BZOJ 2330: [SCOI2011]糖果【差分約束】

2330: [SCOI2011]糖果

【題目描述】
傳送門

【題解】

這題就是差分約束的裸題,建邊然後刷正環就可以了。

程式碼如下

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 100005
using namespace std;
int n,K,hd,tl,dst[MAXN],que[MAXN],Tim[MAXN];
long long Ans;
bool vis[MAXN];
int tot,lnk[MAXN],nxt[4
*MAXN],son[4*MAXN],w[4*MAXN]; void Add(int x,int y,int z){son[++tot]=y,w[tot]=z,nxt[tot]=lnk[x],lnk[x]=tot;} bool SPFA(int x){ hd=0,que[tl=1]=x,Tim[x]=1;vis[x]=1; while(hd^tl){ x=que[(++hd)%=MAXN];vis[x]=0; for(int j=lnk[x];j;j=nxt[j]) if(dst[x]+w[j]>dst[son[j]]){ dst[son[j]]=dst[x]+w[j]; if
(++Tim[son[j]]>=n) return 0; if(!vis[son[j]]) vis[son[j]]=1,que[(++tl)%=MAXN]=son[j]; } } return 1; } int main(){ #ifndef ONLINE_JUDGE freopen("prob.in","r",stdin); freopen("prob.out","w",stdout); #endif scanf("%d%d",&n,&K); for(int i=1;i<=K;i++){ int
opt,x,y;scanf("%d%d%d",&opt,&x,&y); if(opt==1) Add(x,y,0),Add(y,x,0);else if(opt==2){if(x==y){printf("-1\n");return 0;}Add(x,y,1);}else if(opt==3) Add(y,x,0);else if(opt==4){if(x==y){printf("-1\n");return 0;}Add(y,x,1);}else Add(x,y,0); } for(int i=n;i;i--) Add(0,i,1); if(!SPFA(0)) printf("-1\n");else{ for(int i=1;i<=n;i++) Ans+=dst[i]; printf("%lld\n",Ans); } return 0; }