1. 程式人生 > >BZOJ4602 Sdoi2016 齒輪 【帶權並查集】*

BZOJ4602 Sdoi2016 齒輪 【帶權並查集】*

BZOJ4602 Sdoi2016 齒輪

Description

現有一個傳動系統,包含了N個組合齒輪和M個鏈條。每一個鏈條連線了兩個組合齒輪u和v,並提供了一個傳動比x : y。即如果只考慮這兩個組合齒輪,編號為u的齒輪轉動x圈,編號為v的齒輪會轉動y圈。傳動比為正表示若編號為u的齒輪順時針轉動,則編號為v的齒輪也順時針轉動。傳動比為負表示若編號為u的齒輪順時針轉動,則編號為v的齒輪會逆時針轉動。若不同鏈條的傳動比不相容,則有些齒輪無法轉動。我們希望知道,系統中的這N個組合齒
輪能否同時轉動。

Input

有多組資料,第一行給定整數T,表示總的資料組數,之後依次給出T組資料。每一組資料的第一行給定整數N和M,表示齒輪總數和鏈條總數。之後有M行,依次描述了每一個鏈條,其中每一行給定四個整數u,v,x和y,表示只考慮這一組聯動關係的情況下,編號為u的齒輪轉動x圈,編號為v的齒輪會轉動y圈。請注意,x為正整數,而y為非零整數,但是y有可能為負數。
T<=32,N<=1000,M<=10000且x與y的絕對值均不超過100

Output

輸出T行,對應每一組資料。首先應該輸出標識這是第幾組資料,參見樣例輸出。之後輸出判定結果,如果N個組合
齒輪可以同時正常執行,則輸出Yes,否則輸出No。

Sample Input

2
3 3
1 2 3 5
2 3 5 -7
1 3 3 -7
3 3
1 2 3 5
2 3 5 -7
1 3 3 7

Sample Output

Case #1: Yes
Case #2: No

思路就是帶權並查集
因為必須滿足任意一個環上的比值相乘為1
所以就可以用帶權並查集維護了

需要注意的是在合併兩個節點u,vu,v的時候
fa[fau]=favfa[fau]=fav

]=fav
dis[fau]=dis[v]/dis[u]x/ydis[fau]=dis[v]/dis[u]*x/y
需要滿足上面兩個式子,主要是為了抵消方向和多餘比例u&gt;fau,v&gt;favu-&gt;fau,v-&gt;fav的影響

#include<bits/stdc++.h>
using namespace std;
#define N 10010
#define eps 1e-3
int fa[N];double dis[N];
int n,m;
void
init(){for(int i=1;i<=n;i++)fa[i]=i,dis[i]=1.0;} bool euq(double x){return abs(x-1)<=eps;} int find(int x){ if(x==fa[x])return x; int fax=fa[x]; fa[x]=find(fax); dis[x]*=dis[fax]; return fa[x]; } int main(){ int T;scanf("%d",&T); for(int t=1;t<=T;t++){ scanf("%d%d",&n,&m); init(); bool can=1; for(int i=1;i<=m;i++){ int u,v;double x,y; scanf("%d%d%lf%lf",&u,&v,&x,&y); int fau=find(u); int fav=find(v); if(fau==fav){ if(!euq(dis[u]/dis[v]/x*y)){ can=0; break; } }else{ fa[fau]=fav; dis[fau]=dis[v]/dis[u]*x/y; } } printf("Case #%d: ",t); printf((can)?"Yes\n":"No\n"); } return 0; }