W3 school 菜鸟教程 我要自学网 信息学奥赛NOI 花哥的博客 不逼自己一把,怎知自己有多优秀——校长语录

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;
}

 

posted @ 2020-04-04 15:11  耍人  阅读(392)  评论(0编辑  收藏  举报