超级SB题,写题解纯粹是为了水博客,刚开始WA了一发因为又被题意杀了,我以为不连通就不能同时转(脑洞清奇)
首先我们容易想到先给原图同一颗生成树出来(不连通的话就是森林),然后假定某个点转\(1\)圈,顺带求出其它每个点转的圈数
然后再枚举非生成树边,判断是否可行即可,注意精度要用EPS
判断
PS:本来对于乘除法的精度问题应该取对数变加减法的,然后这里数据范围小懒了随便写了一发就过了233
#include<cstdio>
#include<cmath>
#define RI register int
#define CI const int&
using namespace std;
const int N=1005,M=10005;
const double EPS=1e-6;
struct edge
{
int fr,to,nxt,x,y;
}e[M<<1]; int t,cases,head[N],cnt,n,m,u,v,x,y,q[N]; double r[N]; bool vis[N],use[M];
inline void addedge(CI u,CI v,CI x,CI y)
{
e[++cnt]=(edge){u,v,head[u],x,y}; head[u]=cnt;
}
#define to e[i].to
inline void BFS(CI st)
{
RI H=0,T=1; r[q[1]=st]=1.0; vis[st]=1; while (H<T)
{
int now=q[++H]; for (RI i=head[now];i;i=e[i].nxt)
if (!vis[to]) r[to]=r[now]*e[i].x/e[i].y,vis[to]=use[i+1>>1]=1,q[++T]=to;
}
}
#undef to
inline void clear(void)
{
RI i; for (i=1;i<=n;++i) head[i]=vis[i]=0;
for (cnt=0,i=1;i<=m;++i) use[i]=0;
}
int main()
{
for (scanf("%d",&t),cases=1;cases<=t;++cases)
{
RI i; for (scanf("%d%d",&n,&m),i=1;i<=m;++i)
scanf("%d%d%d%d",&u,&v,&x,&y),addedge(u,v,x,y),addedge(v,u,y,x);
for (i=1;i<=n;++i) if (!vis[i]) BFS(i); bool flag=1;
for (i=1;i<=m;++i) if (!use[i])
if (fabs(r[e[i<<1].fr]*e[i<<1].x-r[e[i<<1].to]*e[i<<1].y)>=EPS)
{ flag=0; break; } if (flag) printf("Case #%d: Yes\n",cases);
else printf("Case #%d: No\n",cases); clear();
}
}