BZOJ 4602: [Sdoi2016]齿轮

超级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();
    }
}

猜你喜欢

转载自www.cnblogs.com/cjjsb/p/12243254.html