[SDOI2016] BZOJ4602 齿轮-dfs-带权并查集-数论逆元-质因数分解

40 篇文章 0 订阅
27 篇文章 0 订阅

传送门

题解:

总结几种做法,并指出其中的优劣;

主要是两种算法,一种是暴力dfs,另一种是并查集。

事实上这种“每条边都考虑”大概都可以用上述两种办法处理,并查集复杂度略高,但是其实近乎线性。

暴力dfs就是,建一张无向图(不能是有向的),然后对于每个联通块,第一个元素设为1,然后通过第一个元素,

算出其它元素的值,然后对于点x,以及边(x,y),如果y也访问过了,就判断一下通过x算的y和已经算出来的y是否相等即可。

并查集是类似的,因为是无向图,先加边加成树(或者森林),然后之后在加边就判断即可。

其实这题最主要的是精度问题。

但是出题人特别良心没有卡精度,double都水过去了。

精度控制的几种办法:

第一种,最好想的,直接上double(或者long double)。

问题:数据理论最大是100^1000的,理论上会爆(事实没有)。

第二种,比较容易想到的,取对数,变成加减运算。

问题:可以卡精度,例如1e18和(1e9-1)*(1e9+1)。但是也没有卡。

第三种,在模质数意义下进行运算,除法变成乘逆元,判断类似哈希。

问题:理论上会冲突,实际上不会(几乎不会)。

第四种,注意到x,y<=100可以质因数分解。

问题:这个应该能够保证正确,但是常数略大,(尽管对于这个题是足够的)。

代码:用的是第一种SB方法竟然没有被卡QwQ

//BZOJ 4602
//SDOI 2016
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define MAXN 1100
#define MAXM 21000
using namespace std;
struct edges{
	int to,pre;
	double wgt;
}e[MAXM];
int h[MAXN],etop;
int add_edge(int u,int v,double wgt)
{
	etop++;
	e[etop].to=v;
	e[etop].pre=h[u];
	e[etop].wgt=wgt;
	h[u]=etop;
	return 0;
}
double val[MAXN];
const double ep=0.000001;
bool vis[MAXN];
bool dcmp(double x)
{
	if(fabs(x)<ep) return false;
	else return true;
}
bool dfs(int x)
{
	vis[x]=true;
	for(int i=h[x];i;i=e[i].pre)
		if(!vis[e[i].to])
		{
			val[e[i].to]=val[x]*e[i].wgt;
			if(!dfs(e[i].to)) return false;
		}
		else if(dcmp(val[e[i].to]-val[x]*e[i].wgt)) return false;
	return true;
}
int main()
{
	int T;scanf("%d",&T);
	for(int t=1;t<=T;t++)
	{
		int n,m;scanf("%d%d",&n,&m);
		memset(h,0,sizeof(h));etop=0;
		memset(vis,false,sizeof(vis));
		for(int i=1;i<=m;i++)
		{
			int u,v,x,y;scanf("%d%d%d%d",&u,&v,&x,&y);
			add_edge(u,v,(double)y/x);
			add_edge(v,u,(double)x/y);
		}
		for(int i=1;i<=n;i++)
			if(!vis[i])
			{
				val[i]=1.0;
				if(!dfs(i))
				{
					printf("Case #%d: No\n",t);
					goto loop;
				}
			}
		printf("Case #%d: Yes\n",t);
		loop:;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值