• 1437:扩散


    1437:扩散(一本通网站原题链接)

    【分析】

      本题初看很是高兴,虽然数值较大,但数据量很小,随便折腾都不会超时。再看本题所需解决的问题,1:如何确定点的连通。这个问题很熟悉,之前高中数学中有一个题目:在画有方格的纸上有两个格点A、B,一只蚂蚁从A沿网格线爬到B的最短路径有多少条。其实就是横格与竖格的排列。这个就更简单了,数横格与竖格的和作为两点的距离。两个点都在扩散,相当于速度为2,经过多少时间可以连通就可以计算了。2:图的连通性。这个有模式了,可以用集合的方法。我用的集合合并的方法,全图连通了,每个点的祖先都一样,每个点的祖先的成员个数就是n。3:最少时间的计算。这个几乎是个倒序了。其实我们应该是知道时间才知道点的连通性,也才知道图的连通性,所以,我们可以用二分法试确定。

      整体来看,这个题目还是不错的,虽然没有超时的危险,但对基础方法算是个复习。

    【AC代码】

    //1437:扩散
    #include<iostream>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    int const N=101,inf=0x7fffffff;
    ll x[N],y[N],d[N][N],fa[N],num[N],n,l=inf,r,ti,tj,mid;
    int pa(int tx)
    {
        if(fa[tx]!=tx)fa[tx]=pa(fa[tx]);
        return fa[tx];
    }
    bool ts(int t)
    {
        for(int i=1;i<=n;i++)fa[i]=i,num[i]=1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(d[i][j]<=t*2)
                {
                    ti=pa(i);
                    tj=pa(j);
                    if(ti!=tj)
                    fa[tj]=ti,num[ti]+=num[tj];
                }
        return num[pa(1)]==n;
    }
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++)cin>>x[i]>>y[i];
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                d[i][j]=abs(x[i]-x[j])+abs(y[i]-y[j]);
                if(l>d[i][j])l=d[i][j];
                if(r<d[i][j])r=d[i][j];
            }
        l/=2,r=(r+1)/2;
        while(l+1<r)
        {
            mid=(l+r)/2;
            if(ts(mid))r=mid;
            else l=mid;
        }
        cout<<r;
        return 0;
    }
  • 相关阅读:
    C++默认参数
    C++中对象初始化
    类设计者的核查表
    函数返回数组
    UVA439 骑士的移动 Knight Moves
    P2415 集合求和(一道洛谷好题鸭)(虽然可以水过,但有必研究DP)
    最小生成树(Kruskal)
    并查集(许多东西的基本哦)
    堆模板(STL版)
    线段树模板(贼慢的版本)
  • 原文地址:https://www.cnblogs.com/wendcn/p/12631958.html
Copyright © 2020-2023  润新知