BZOJphp
差分約束:html
太真實了= = 插個廣告:這裏有差分約束詳(並不)解。spa
記\(r_i\)爲第\(i\)行總體加了多少的權值,\(c_i\)爲第\(i\)列總體加了多少權值,那麼限制\((i,j),k\)就是\(r_i+c_j=k\)。
這就是差分約束裸題了。\(r_i+c_j=k\Rightarrow r_i-(-c_j)\leq k\ \&\&\ -c_j-r_i\leq -k\)。
注意形式是\(x_j-x_i\leq w\)=v=
建邊跑最短路判負環便可。.net
去洛谷複習之前的板子(忘了怎麼寫了=-=),發現DFS判負環被卡掉了?太棒啦不用背DFS的代碼惹。
乖乖寫BFS好了。pwa
帶權並查集:
發現這題和BZOJ1202是如出一轍的= =。由於全是相等關係,實際上是十分特殊的差分約束,能夠用帶權並查集作。
記\(fa[x]\)表示\(x\)所在集合的根節點,\(dis[x]\)表示\(x\)到\(fa[x]\)的實際距離。
所謂距離是指:對於\(r+c=k\),變成\(r-(-c)=k\),即\(r\)比\(-c\)大\(k\),就在\(r\to -c\)之間連距離爲\(k\)的邊,同時令\(fa[r]=-c\)。
這樣對於一個限制\(r,c,k\),若是\(r,c\)不在同一集合就合併(令較大的數的祖先是較小的數)。在並查集\(Find\)過程當中順便維護一下\(dis\)(具體見代碼好惹,注意變量賦值順序)。
若是\(r,c\)在同一集合,就根據\(dis\)差判一下它倆的距離是否等於\(k\)。code
就算\(k\)多是負的這麼作也沒什麼問題。(廢話=v=)htm
差分約束:blog
//904kb 48ms #include <queue> #include <cstdio> #include <cctype> #include <cstring> #include <algorithm> #define gc() getchar() typedef long long LL; const int N=2005; int Enum,H[N],nxt[N],to[N],len[N],dis[N],dgr[N]; bool vis[N],inq[N]; inline int read() { int now=0,f=1;register char c=gc(); for(;!isdigit(c);c=='-'&&(f=-1),c=gc()); for(;isdigit(c);now=now*10+c-48,c=gc()); return now*f; } inline void AE(int u,int v,int w) { to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum, len[Enum]=w; } bool SPFA(int s,int n)//怎麼都直接拿n作總點數的=-= 強迫症表示不行 { std::queue<int> q; q.push(s), dis[s]=0; while(!q.empty()) { int x=q.front(); q.pop(); inq[x]=0; for(int i=H[x],v; i; i=nxt[i]) if(dis[v=to[i]]>dis[x]+len[i]) { if(++dgr[v]>n) return 1; dis[v]=dis[x]+len[i], !inq[v]&&(q.push(v),inq[v]=1); } } return 0; } int main() { for(int Ts=read(); Ts--; ) { int n=read(),m=read(),tot=n+m,cnt=0; Enum=0, memset(H,0,tot+1<<2), memset(vis,0,tot+1); for(int u,v,w,K=read(); K--; ) { u=read(),v=read()+n,w=read(); AE(v,u,w), AE(u,v,-w); if(!vis[u]) vis[u]=1, ++cnt; if(!vis[v]) vis[v]=1, ++cnt; } memset(dis,0x7f,tot+1<<2), memset(dgr,0,tot+1<<2), memset(inq,0,tot+1); bool fg=1; for(int i=1; i<=tot; ++i) if(vis[i]&&dis[i]==dis[0]&&SPFA(i,cnt)) {fg=0; break;} puts(fg?"Yes":"No"); } return 0; }
帶權並查集:get
//836kb 20ms #include <cstdio> #include <cctype> #include <assert.h> #include <algorithm> #define gc() getchar() typedef long long LL; const int N=2005; int fa[N],dis[N]; inline int read() { int now=0,f=1;register char c=gc(); for(;!isdigit(c);c=='-'&&(f=-1),c=gc()); for(;isdigit(c);now=now*10+c-48,c=gc()); return now*f; } int Find(int x) { if(x==fa[x]) return x; int t=fa[x]; fa[x]=Find(t), dis[x]+=dis[t];//!!! return fa[x]; } int main() { for(int Ts=read(); Ts--; ) { const int n=read(),m=read(),tot=n+m; for(int i=1; i<=tot; ++i) fa[i]=i, dis[i]=0; bool fg=1; for(int u,v,w,K=read(); K--; ) { u=read(),v=read()+n,w=read(); if(!fg) continue; int r1=Find(u),r2=Find(v); if(r1!=r2) fa[r1]=r2, dis[r1]=dis[v]+w-dis[u]; else if(dis[u]-dis[v]!=w) fg=0; } puts(fg?"Yes":"No"); } return 0; }