Hoofball [codeforces] (思维题)

原题传送门


题面:

Hoofball

                                 time limit per test : 5 seconds
                              memory limit per test : 512 megabytes
                                     input : standard input
                                    output : standard output

Problem Description

In preparation for the upcoming hoofball tournament, Farmer John is drilling his N cows (conveniently numbered 1…N, where 1≤N≤100) in passing the ball. The cows are all standing along a very long line on one side of the barn, with cow i standing xi units away from the barn (1≤xi≤1000). Each cow is standing at a distinct location.

At the beginning of the drill, Farmer John will pass several balls to different cows. When cow i receives a ball, either from Farmer John or from another cow, she will pass the ball to the cow nearest her (and if multiple cows are the same distance from her, she will pass the ball to the cow farthest to the left among these). So that all cows get at least a little bit of practice passing, Farmer John wants to make sure that every cow will hold a ball at least once. Help him figure out the minimum number of balls he needs to distribute initially to ensure this can happen, assuming he hands the balls to an appropriate initial set of cows.

Input

The first line of input contains N. The second line contains N space-separated integers, where the ith integer is xi.

Ouput

Please output the minimum number of balls Farmer John must initially pass to the cows, so that every cow can hold a ball at least once.

Sample Input

5
7 1 3 11 4

Sample Output

2

题意描述

牛会把球踢给离它最近的牛,若两边都离它最近,他就会把球踢给左边的牛.John想用最少数量的球让全部牛都能拿到一次球.

题目分析

动态规划.枚举每一头牛作为开球牛Cow0,找到球转移的区间,有 dp[i] = min( dp[i] , dp[cow-1]+1 ).而作为球转移的区间结尾特征是已经踢过球的牛会再次作为下一头踢球的牛.所以可以用一个vis数组记录哪些牛在Cow0作为开球牛的踢球区间内已经踢过球.

具体代码

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
int cow[105];
bool vis[105];
bool fx[105];
int dp[105];
int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &cow[i]);
    }
    sort(cow+1, cow+n+1);
    fx[1] = true, fx[n] = false;//true代表向右踢,false代表向左  第一头牛必定向右,最后一头必定向左
    for(int i = 2; i <= n-1; i++)
    {
        if(cow[i]-cow[i-1] <= cow[i+1]-cow[i])
        {
            fx[i] = false;
        }
        else
        {
            fx[i] = true;
        }
    }
    memset(dp, inf, sizeof(dp));
    dp[0] = 0;
    for(int i = 1; i <= n; i++)
    {
        memset(vis, false, sizeof(vis));//重置vis,代表所有牛都未访问
        vis[i] = true;
        int maxx = i;
        int minx = i;
        int nxt = fx[i] ? i+1 : i-1;
        while(!vis[nxt])//当下一头牛未访问时继续,若下一头牛已被访问则说明球踢回来了
        {
            vis[nxt] = true;
            maxx = max(maxx , nxt);
            minx = min(minx , nxt);
            nxt = fx[nxt] ? nxt+1 : nxt-1;
        }
        if(minx != i)
        {
            for(int j = minx; j <= i; j++)
            {
                dp[j] = min(dp[j] , dp[minx-1]+1);
            }
        }
        else
        {
            for(int j = i; j<= maxx; j++)
            {
                dp[j] = min(dp[j] , dp[i-1]+1);
            }
        }
    }
    printf("%d\n", dp[n]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值