【NOIP2014模拟8.24】小X 的道路修建

8 篇文章 0 订阅
在一场地震后,Y省需重建n个城市的道路网络,仅能修建m条道路。省长要求用最少的道路连接所有城市,并使最贵与最便宜道路价格差最小。解决方案是按边权值从小到大排序,逐条加入,若形成环则删除原树中最大边,确保差值最小。当形成一棵树时,更新答案为当前最大边权减去树中最小边权。
摘要由CSDN通过智能技术生成

题目

因为一场不小的地震,Y 省n 个城市之间的道路都损坏掉了,省长希望小X 将城市之间的道路重修一遍。
很多城市之间的地基都被地震破坏导致不能修路了,因此可供修建的道路只有m 条。因为施工队伍有限,省长要求用尽量少的道路将所有的城市连通起来,这样施工量就可以尽量少。不过,省长为了表示自己的公正无私,要求在满足上述条件的情况下,选择一种方案,使得该方案中最贵道路的价格和最便宜道路的价格的差值尽量小,即使这样的方案会使总价提升很多也没关系。
小X 现在手忙脚乱,希望你帮帮他。

分析

我们将边按权值从小到大排序
将边一条条加入,
当当前边的两个端点在原树中有路径相连时,如果加入的当前边,就会形成一个环,
所以将当前边的两个端点在原树中的路径中的最大一条边删掉,这样就能保证差值尽量小。
然后,如果形成了一棵树,就将当前边的边权(因为排了序,当前边的边权一定最大)-树中最小的边权来更新答案。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const int mo=1000000007;
const int N=3005;
using namespace std;
int k,n,m,fa[N*N*2],a[N][N*2],ans;
int z[8][2]=
{
    {-1,0},
    {0,-1},
    {1,0},
    {0,1},
    {-1,1},
    {1,-1},
    {1,1},
    {-1,-1}
};
int pos(int x,int y)
{
    return (x-1)*m*2+y;
}
int get(int x)
{
    if(fa[x]==x) return x;
    fa[x]=get(fa[x]);
    return fa[x];
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n*m*2;i++) fa[i]=i;
    for(k=k;k>=1;k--)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        int xx=x,yy=y+m;
        bool q=true;
        for(int i=0;i<=7 && q;i++)
            if(a[x+z[i][0]][(y+z[i][1]-1+2*m)%(2*m)+1])
            {
                int xf=get(pos(x+z[i][0],(y+z[i][1]-1+2*m)%(2*m)+1));
                for(int j=0;j<=7 && q;j++)
                    if(a[xx+z[j][0]][(yy+z[j][1]-1+2*m)%(2*m)+1])
                    {
                        int yf=get(pos(xx+z[j][0],(yy+z[j][1]-1+2*m)%(2*m)+1));
                        if(xf==yf) q=false;
                    }
            }
        if(q)
        {
            a[x][y]=a[xx][yy]=1;
            for(int i=0;i<=7;i++)
                if(a[x+z[i][0]][(y+z[i][1]-1+2*m)%(2*m)+1])
                {
                    int xf=get(pos(x+z[i][0],(y+z[i][1]-1+2*m)%(2*m)+1));
                    fa[xf]=pos(x,y);
                }
            for(int j=0;j<=7;j++)
                if(a[xx+z[j][0]][(yy+z[j][1]-1+2*m)%(2*m)+1])
                {
                    int yf=get(pos(xx+z[j][0],(yy+z[j][1]-1+2*m)%(2*m)+1));
                    fa[yf]=pos(xx,yy);
                }
            ans++;
        }
    }
    cout<<ans<<endl;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值