洛谷 P3073 [USACO13FEB]拖拉机Tractor

洛谷 P3073 [USACO13FEB]拖拉机Tractor

Description

  • FJ有块农田太崎岖了,他要买一辆新拖拉机才能在这里巡视。这块农田由N x N个格子的非负整数表示高度(1<=N<=500)。拖拉机从当前格子走到相邻格子(东、南、西、北四个方向)的代价为高度差D,则FJ驶过这两个格子的拖拉机最少也要值D块钱。

    FJ愿意花足够的钱买一辆新的拖拉机使得他能以最小的高度差走遍所有格子的一半(如果格子总数是奇数,那么一半的值为四舍五入的值)。因为FJ很懒,所以他找到你帮他编程计算他最小需要花多少钱买到符合这些要求的拖拉机。

Input

  • 第一行为一个整数N

    第2到N+1行每行包含N个非负整数(不超过1,000,000),表示当前格子的高度。

Output

  • 共一行,表示FJ买拖拉机要花的最小价钱。

Sample Input

5 
0 0 0 3 3 
0 0 0 0 3 
0 9 9 3 3 
9 9 9 3 3 
9 9 9 9 3 

Sample Output

3 

题解:

  • 最小生成树。
  • 首先每个格子都跟它周围的格子建边。然后将边权从小到大排序依次加入。每加入一条边后,判断是否有集合里的元素超过了一半格子数。如果超过了,直接输出这条边的权即可。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define N 505
#define M (500 * 500 * 2)
using namespace std;

struct E {int u, v, w;} e[M];
int n, tot, cnt, ans;
int fat[N * N], size[N * N];
int a[N][N];

int cal(int x, int y) {return (x - 1) * n + y;}
bool cmp(E x, E y) {return x.w < y.w;}

int getFat(int x)
{
    if(x == fat[x]) return x;
    return fat[x] = getFat(fat[x]);
}

int main()
{
    cin >> n, tot = n * n / 2;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            scanf("%d", &a[i][j]);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
        {
            int x = i, y = j + 1;
            if(x >= 1 && x <= n && y >= 1 && y <= n)
            {
                e[++cnt].u = cal(i, j);
                e[cnt].v = cal(x, y);
                e[cnt].w = abs(a[i][j] - a[x][y]);
            }
            x = i + 1, y = j;
            if(x >= 1 && x <= n && y >= 1 && y <= n)
            {
                e[++cnt].u = cal(i, j);
                e[cnt].v = cal(x, y);
                e[cnt].w = abs(a[i][j] - a[x][y]);
            }
        }
    for(int i = 1; i <= n * n; i++)
        fat[i] = i, size[i] = 1;
    sort(e + 1, e + 1 + cnt, cmp);
    for(int i = 1; i <= cnt; i++)
    {
        int fx = getFat(e[i].u), fy = getFat(e[i].v);
        if(fx == fy) continue;
        if(size[fx] > size[fy]) swap(fx, fy);
        size[fy] += size[fx], fat[fx] = fy;
        if(size[fy] >= tot) {cout << e[i].w; break;}
    }
    return 0;
}

转载于:https://www.cnblogs.com/BigYellowDog/p/11505418.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值