LGOJ3101 [USACO14JAN]滑雪等级Ski Course Rating

LGOJ3101 [USACO14JAN]滑雪等级Ski Course Rating


【问题描述】

The cross-country skiing course at the winter Moolympics is described by an M x N grid of elevations (1 <= M,N <= 500), each elevation being in the range 0 .. 1,000,000,000.

Some of the cells in this grid are designated as starting points for the course. The organizers of the Moolympics want to assign a difficulty rating to each starting point. The difficulty level of a starting point P should be the minimum possible value of D such that a cow can successfully reach at least T total cells of the grid (1 <= T <= MN), if she starts at P and can only move from cell to adjacent cell if the absolute difference in elevation between the cells is at most D. Two cells are adjacent if one is directly north, south, east, or west of the other.

Please help the organizers compute the difficulty rating for each starting point.

滑雪场用一个M*N(1 <= M,N <= 500)的数字矩阵表示海拔高度,每个数字表示一个范围在0 .. 1,000,000,000的高度。有些格子被指定为起点,组织者想对这些起点做难度评级。

如果起点P点是一个难度级别为D的起点,则D必须是满足以下条件的一个最小值:

(1)从一个格子只能滑到相邻的格子;

(2)这两个格子的海拔差不超过D;

(3)至少能够到达T(1 <= T <= M*N)个格子(包括起点本身)。

【输入样例】

3 5 10
20 21 18 99 5
19 22 20 16 17
18 17 40 60 80
1 0 0 0 0
0 0 0 0 0
0 0 0 0 1

【输出样例】

24


#include<bits/stdc++.h>
using namespace std;
const int maxn = 500 + 5;
const int maxm = maxn * maxn;
long long am[maxm], fa[maxm], is[maxm];
//am amount 集合子点数量 ,fa father 父节点编号 , is is_start 集合内的起点个数 
long long he[maxn][maxn], id[maxn][maxn];
//he height (i,j)高度  
long long n, m, t, cntv, sign, cnte;
//cntv count_vertex,cnte count_edge  
struct edge
{
    long long beg, to, len; // beg起点 , to 终点 ,len 边权 
} a[1000000]; //血泪(必须要开1000000) 
edge mk(long long x,long long  y, long long z)
{
    edge t = (edge)
    {
        x, y, z
    };
    return t;
}//这是一个制作边的函数 
bool cmp(edge a, edge b)
{
    return a.len < b.len;
}//这是一个将边排序的函数(服务于贪心思想) 
long long find(long long x)
{
    if(x == fa[x])return x;
    else return fa[x] = find(fa[x]);
}//并查集标准find函数 
void merge(int x, int y)
{
    if(x < y)swap(x, y);

    fa[y] = x;
    am[x] += am[y];
  //  am[y] = 0;
    is[x] += is[y];
}//这是一个合并函数(维护了两个集合的子点数个数,起点个数) 
int main()
{
    scanf("%lld%lld%lld", &n, &m, &t);

    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            scanf("%lld", &he[i][j]);
            cntv++;
            id[i][j] = cntv;
            //给坐标为(i,j)的点编号 cntv
        }
    } 
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            scanf("%lld", &sign);

            if(sign)is[id[i][j]] = 1;//这个点是一个起点 

            if(i < n)
            {
                a[++cnte] = mk(id[i][j], id[i + 1][j], abs(he[i][j] - he[i + 1][j]));
            }

            if(j < m)
            {
                a[++cnte] = mk(id[i][j], id[i][j + 1], abs(he[i][j] - he[i][j + 1]));
            }
            
            //建边 
        }
    }

    sort(a + 1, a + 1 + cnte, cmp);
    
    //贪心 
     
    long long ans = 0;

    for(int i = 1; i <= maxm; i++)
    {
        am[i] = 1; //i是自己的一个集 
        fa[i] = i;
    }
    for(int i = 1; i <= cnte; i++)
    {
        int x = a[i].beg;
        int y = a[i].to;
        int z = a[i].len;
        int fx = find(x);
        int fy = find(y);
        if(fx==fy)continue; 
        
        if(am[fx] + am[fy] >= t)
        {
            if(am[fx] < t)ans += z * is[fx];
            //如果一个集合的数目小于t,则其没有算过边。    
            if(am[fy] < t)ans += z * is[fy];
        }

        merge(fx, fy);
    }

    printf("%lld", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/yangxuejian/p/10993576.html
今日推荐