BZOJ4602 Sdoi2016 齒輪 【帶權並查集】*
阿新 • • 發佈:2019-02-01
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
所以就可以用帶權並查集維護了
需要注意的是在合併兩個節點的時候
需要滿足上面兩個式子,主要是為了抵消方向和多餘比例的影響
#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;
}