4602: [Sdoi2016]齿轮

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 613  Solved: 324
[Submit][Status][Discuss]

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

HINT

 

Source

【民间做法】:DFS
//对于每组齿轮(u, v)连边,权值为y/x(反向边x/y)
//dfs 判断矛盾
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef double real;
inline void read(int &x){
register char ch=getchar();int f=1;x=0;
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
x*=f;
}
const int N=1e5+5;
const real eps=1e-6;
struct edge{int v,next;real w;}e[N<<1];int tot,head[N];
int T,n,m,cas;
bool vis[N],flag;
real val[N];
inline void add(int x,int y,real z){
e[++tot].v=y;e[tot].w=z;e[tot].next=head[x];head[x]=tot;
}
inline bool dfs(int x,real sp){
vis[x]=1;
val[x]=sp;
for(int i=head[x];i;i=e[i].next){
if(!vis[e[i].v]){
if(dfs(e[i].v,sp*e[i].w))
return 1;
}
else{
if(fabs(val[e[i].v]-sp*e[i].w)>eps)
return 1;
}
}
return 0;
}
inline void clr(){
tot=0;flag=0;
memset(head,0,(n+1)<<2);
memset(vis,0,(n+1)<<2);
}
int main(){
for(read(T);T--;clr()){
read(n);read(m);
for(int i=1,u,v,x,y;i<=m;i++){
read(u);read(v);
read(x),read(y);
add(u,v,(real)y/(real)x);
add(v,u,(real)x/(real)y);
}
for(int i=1;i<=n;i++) if(!vis[i]){
if(dfs(i,1)){
flag=1;break;
}
}
printf("Case #%d: %s\n",++cas,flag?"No":"Yes");
}
return 0;
}
【官方做法】:加权并查集

首先可以看出这个齿轮的转动关系是具有传递性的,如果知道x和y的关系,也知道y和z的关系,就可以推出x和z的关系。具有这种关系的东西一般都可以用加权并查集来搞。对于每个元素给它维护一个dis[x],表示的含义是如果x的代表元素转动1圈,x要转动几圈。每次读入一个限制如果x和y不在同一个集合里就进行合并。合并的时候先找到x的代表元素r1和y的代表元素r2,然后我们要把r2合并到r1上。要进行合并就要知道r1转一圈的时候r2转几圈。设从读入的信息可以知道x转一圈的时候y转w圈,那么如果r1转了一圈,y就转了dis[x]∗w圈;而当y转了dis[x]∗w圈的时候,r2转了dis[x]∗w/dis[y]圈。关系如下图:
 
如果读入的x和y在一个集合里,那么就可以用维护的信息算出x转了一圈的时候y转了几圈,和读入的信息进行比对就可以判定是否发生矛盾。

这个数据范围看起来好像很小的样子。。但是如果它出上n-1个信息,每次都是当齿轮i转动1圈的时候齿轮i+1转动100圈,那么最后就会发现当齿轮1转动一圈的时候齿轮n会转动100n圈。。这样的话就不能直接用int或者long
long或者什么类似的东西来维护加权并查集的dis了。。用分解质因数似乎是比较稳的方法,但是听说用long double还是什么类似的东西也能过?

#include<cmath>
#include<cstdio>
using namespace std;
typedef double real;
inline void read(int &x){
register char ch=getchar();int f=1;x=0;
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
x*=f;
}
const int N=1e5+5;
const real eps=1e-6;
int T,n,m,cas;bool flag;
int fa[N];real dis[N];
int find(int x){
int t;
if(fa[x]!=x) t=find(fa[x]),dis[x]*=dis[fa[x]],fa[x]=t;
return fa[x];
}
int main(){
for(read(T);T--;flag=0){
read(n);read(m);
for(int i=1;i<=n;i++) fa[i]=i,dis[i]=1;
for(int i=1,r1,r2,u,v,x,y;i<=m;i++){
read(u);read(v);read(x);read(y);
r1=find(u);r2=find(v);
if(r1==r2){
if(fabs(dis[v]/dis[u]-(real)y/(real)x)>eps){
flag=1;break;
}
}
else{
fa[r2]=r1;
dis[r2]=(dis[u]*y)/(dis[v]*x);
}
}
printf("Case #%d: %s\n",++cas,flag?"No":"Yes");
}
return 0;
}

[Sdoi2016]齿轮的更多相关文章

  1. BZOJ 4602: [Sdoi2016]齿轮 dfs

    4602: [Sdoi2016]齿轮 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4602 Description 现有一个传动系统,包 ...

  2. BZOJ4602 Sdoi2016 齿轮 【带权并查集】*

    BZOJ4602 Sdoi2016 齿轮 Description 现有一个传动系统,包含了N个组合齿轮和M个链条.每一个链条连接了两个组合齿轮u和v,并提供了一个传动比x : y.即如果只考虑这两个组 ...

  3. bzoj 4602: [Sdoi2016]齿轮

    4602: [Sdoi2016]齿轮 Description 现有一个传动系统,包含了N个组合齿轮和M个链条.每一个链条连接了两个组合齿轮u和v,并提供了一个传动比x  : y.即如果只考虑这两个组合 ...

  4. BZOJ4602:[SDOI2016]齿轮(并查集)

    Description 现有一个传动系统,包含了N个组合齿轮和M个链条.每一个链条连接了两个组合齿轮u和v,并提供了一个传动比x  : y.即如果只考虑这两个组合齿轮,编号为u的齿轮转动x圈,编号为v ...

  5. 【bzoj4602】[Sdoi2016]齿轮 BFS

    题目描述 给出一张n个点m条边的有向图,每条边 (u,v,x,y) 描述了 u 的点权乘 x 等于 v 的点权乘 y (点权可以为负).问:是否存在满足条件的图. 输入 有多组数据,第一行给定整数T, ...

  6. BZOJ4602 SDOI2016齿轮(搜索)

    dfs一遍给每个齿轮随便标个值看是否矛盾就行了. #include<iostream> #include<cstdio> #include<cmath> #incl ...

  7. bzoj4602 [Sdoi2016]齿轮

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4602 [题解] 对于每组齿轮(u, v)连边,权值为y/x(反向边x/y) 那么直接dfs计 ...

  8. [bzoj4602][Sdoi2016]齿轮——dfs

    题目 现有一个传动系统,包含了N个组合齿轮和M个链条.每一个链条连接了两个组合齿轮u和v,并提供了一个传动比x : y.即如果只考虑这两个组合齿轮,编号为u的齿轮转动x圈,编号为v的齿轮会转动y圈.传 ...

  9. NC20583 [SDOI2016]齿轮

    题目链接 题目 题目描述 现有一个传动系统,包含了N个组合齿轮和M个链条.每一个链条连接了两个组合齿轮u和v,并提供了一个传动比x : y. 即如果只考虑这两个组合齿轮,编号为u的齿轮转动x圈,编号为 ...

随机推荐

  1. NFS 网络挂载问题 解决

            在进行嵌入式开发时,通常使用nfs,在开发板上面远程挂载主机上的目录,这样,省去了拷贝复制文件的过程,加快开发速度.在这里,给出自己在nfs相关的设置上出现的问题.         本 ...

  2. thinkphp 3.2 多表查询 group

    分析一 $res = M('member') ->table('__MEMBER__ as a') ->join('__ORDER__ as b') ->field('a.id,b. ...

  3. Lua点号和冒号区别

    定义的时候冒号默认接收self参数调用的时候冒号默认传递调用者自己为参数而句号要显示传递或接收self参数 -- 例如:句号定义,需要显示传递或接收 a = { x = } function a.fu ...

  4. Linux同时安装python2和Python3

    我们以Ubuntu 为例,默认地,Linux安装好后会默认安装python2版本: 安装Python3: For Debian:   [user@host]$ sudo apt-get install ...

  5. Java开发者需要学习的移动开发编程语言

    编程语言(programming language),是用来定义计算机程序的形式语言.它是一种被标准化的交流技巧,用来向计算机发出指令.一种计算机语言让程序员能够准确地定义计算机所需要使用的数据,并精 ...

  6. yum和apt-get用法及区别

    https://www.cnblogs.com/garinzhang/p/diff_between_yum_apt-get_in_linux.html

  7. ios8 UITableView设置 setSeparatorInset:UIEdgeInsetsZero不起作用的解决办法

    在ios7中,UITableViewCell左侧会有默认15像素的空白.这时候,设置setSeparatorInset:UIEdgeInsetsZero 能将空白去掉. 但是在ios8中,设置setS ...

  8. Data Guard启动实时日志应用

    1. REDO数据实时应用 启动实时应用的优势在于,REDO数据不需要等待归档完成,接收到即可被应用,这样执行角色切换时,操作能够执行得更快,因为日志是被即时应用的. 要启动实时应用也简单,前提是St ...

  9. Windows Server 2008 R2 WSUS服务器的详细配置和部署

    WSUS客户端配置 我们要让客户端计算机能够通过WSUS服务器下载更新程序,而这个设置在域环境和单台PC是的方法不同,这里介绍一下本地计算机如何进行设置. 1.开始--运行--输入gpedit.msc ...

  10. windows自启动脚本

    直接写一个普通批处理文件,如果是需要让它在系统启动时运行, 就将它放在C:\Windows\System32\GroupPolicy\Machine\Scripts\Startup目录下, 如果是需要 ...