1. 程式人生 > >HNOI2005狡猾的商人-差分約束系統

HNOI2005狡猾的商人-差分約束系統

turn val -- return pac const oid std ont

這個題可以用並查集做,這裏是之前一個圖論學傻了的蒟蒻的差分約束做法。。

我們考慮題面中的條件,

若s到t的為w,就相當於sum[t]-sum[s-1]=w。

那麽就是sum[t]-sum[s-1]>=w,sum[t]-sum[s-1]<=w,

同時化成最短路松弛形式得到:sumt[s-1]+w<=sum[t],sum[t]+(-w)<=sum[s-1]。

那麽容易發現,只需要從s-1向t連一條w的邊,再從t向s-1連一條-w的邊就好了。

最後就是直接spfa判環就好了。

#include <bits/stdc++.h>
using namespace std;
inline 
int gi () { int x=0,w=0;char ch=0; while(!(ch>=0&&ch<=9)) { if(ch==-) w=1; ch=getchar(); } while(ch>=0&&ch<=9) x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return w?-x:x; } const int N=110; const int M=2010; bool inq[N]; queue
<int> q; int w,n,m,s,end,Sum,tot,flag,cnt[N],vis[N],head[N],val[N]; struct edge { int next, now, ver; }e[M]; void make (int from, int to, int v) { e[++tot].next=head[from]; head[from]=tot; e[tot].now=to; e[tot].ver=v; } bool SPFA (int k) { memset (val,-0x3f3f3f3f,sizeof
(val)); memset (cnt,0,sizeof (cnt)); memset (inq,0,sizeof (inq)); q.push (k); inq[k]=1, val[k]=0; int x,y,i; while (!q.empty ()) { x=q.front (); q.pop (), inq[x]=0, vis[x]=1; for (i=head[x];i;i=e[i].next) { y=e[i].now; if (val[x]+e[i].ver>val[y]) { if (++cnt[y]>=n) return 0; val[y]=val[x]+e[i].ver; if (!inq[y]) q.push (y), inq[y]=1; } } } return 1; } int main () { w=gi (); while (w--) { n=gi (), m=gi (); tot=0; flag=0; memset (head,0,sizeof (head)); memset (vis,0,sizeof (vis)); memset (&e,0,sizeof (e)); for (int i=1;i<=m;++i) { s=gi (), end=gi (), Sum=gi (); make (s-1, end, Sum), make (end, s-1, -Sum); } for (int i=0;i<=n;++i) { if (vis[i]) continue; if (!SPFA (i)) { flag=1; break; } } flag?printf ("false\n"):printf ("true\n"); } return 0; }

HNOI2005狡猾的商人-差分約束系統