IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 从一道题中学到的 -> 正文阅读

[C++知识库]从一道题中学到的

?题目描述:

2021年的暑假到了,小摩尔们看着手游版波光粼粼的小河,觉得钓鱼会是一个很完美的夏日活动。可是参加活动的摩尔数量太多了,本着爱与和平的原则,为了不让小摩尔们为了争夺场地而吵架,几只聪明的小摩尔决定从一条有着各种各样小鱼的大河修建一个主水道引河水,再通过修建小水道把主水道的河水引到每个小摩尔的家门口。考虑到美观和地形优势,这几只聪明的小摩尔决定按照由东向西的方向修建主水道,而小水道则以由北往南或者由南往北的方向与主水道相连。为了更快竣工,小摩尔们想请你帮帮忙,确定主水道的最优位置并计算出最少需要多久可以修完下水道?

输入格式:

第一行是一个整数n,表示参加钓鱼比赛的摩尔数量(0<n<10000);第二行是一个整数t,表示修建一单位的小水道花费的时间(0<t<10);接下来n行是每位参赛小摩尔的家的位置,每行有两个整数x和y(-10000<x,y<10000),其中x表示东西方向,y表示南北方向。

输出格式:

仅一行,即一个整数,代表最少需要的时间。

样例

样例输入

6

4

3? 7

12? 5

9? 13

20? 1

11 11

211 -5

样例输出:

120

数据范围与提示:

0<n<10000

0<t<10

-10000<x,y<10000


根据题意,我们可以以东西主河道作为x轴,南北作为y轴,发现每一条小河道的距离为距离主河道的距离|y|,而所需时间即是|y|乘以单位时间t,与x无关,也就是说,从第三个数开始,每奇数个数读取后不产生作用,计算式不需要考虑x。

所以解答程序有以下几个要点:

1.构造一个循环,一次读入输入的所有数字,并储存。

2.求得y轴上一点,使得该点距离其他点的距离之和(一次线性)最短

3.求得以该点为x轴时各点纵坐标的绝对值之和。

注意:数据范围(这一点会在之后详细阐述)

以下是第一次的代码

#include<stdio.h>

#include<math.h>



int split(long a[], int low, int high)
{
	int part_element = a[low];

?	for (;;) {
?		while (low < high && part_element <= a[high])
?			high--;
?		if (low >= high)
?			break;
?		a[low++] = a[high];

?		while (low < high && a[low] <= part_element)
?			low++;
?		if (low >= high) break;
?		a[high--] = a[low];
?	}

?	a[high] = part_element;
?	return high;
}

void quicksort(long a[], int low, int high)
{
	int middle;

?	if (low >= high)
?		return;
?	middle = split(a, low, high);
?	quicksort(a, low, middle - 1);
?	quicksort(a, middle + 1, high);
}

int main() {
	long n, num, sum, target;
	int t;
	long x[10];
	long y[10];
	scanf("%d", &n);
	scanf("%d", &t);
	for (long i = 0; i < n; i++)
	{
		x[i] = scanf("%d", &x[i]);
		y[i] = scanf("%d", &y[i]);

?	}

?	quicksort(y, 0, n - 1);
?	if (n % 2 == 0)
?		num = (y[n / 2] + y[n / 2 - 1]) / 2;
?	else
?		num = y[(n/2) ] ;

?	for (long i = 0; i < n; i++) {
?	 sum += abs(y[i] - num);
?	}

?	target = sum * t;
?	printf("%d", target);

?	return 0;
}

我的思路是,使用一个快速排序算法,将y所储存的数字按照从低到高排序,之后取中位数:

当这一系列数字个数为奇数时,中位数到各点距离之和最短;

当这一系列数字个数为偶数时,最中间两点间任意数字到各点距离之和想等且最短。

然而在devC++上代入样例时发现无法得到预期结果。

分析原因:

最开始希望变长数组能够按照输入的数字改变长度,在声明时使用 int x[t]的形式,报错,再看题,数据范围0<t<10,改为 x[10] .

根据输出结果推测,输出=t,可知y的读取和平均数的计算中有一部分出了错。

于是修改代码,首先使用C++库中的sort函数简化;

其次,根据题意,将数组扩大到10000;

修改代码如下:

#include<iostream>
#include<cmath>
#include<stdio.h>
#include<algorithm>







int main() {
	using namespace std;
	int n, target;
	int t;
	int num;

?	scanf("%d", &n);
?	scanf("%d", &t);
?	int a[10000];
?	int b[10000];
?	for (int i = 0; i < n; i++)
?	{
?		scanf("%d", &a[i]);
?		scanf("%d", &b[i]);

?	}
?	
?	sort(b, b + n);
?	if (n % 2 == 0)
?		num = b[n / 2];
?	else if (n == 1)
?		return 0;
?	else 
?		num = ((b[n / 2 - 1] + b[n / 2]) / 2);
?	
  



	int sum = 0;
	for (int i = 0; i < n; i++) {
	sum += abs(b[i] - num);
	}

?	
?	target = t *  sum ;
?	

?	printf("%d\n", target);

?	return 0;
}

代码已经可以满足样例,但oj上只有60分。

继续分析:

测试数据部分可以通过,部分不能。怀疑是奇偶数出错,即中位数出问题。

(最后确实是中位数写反了,但那都是后话了)

当时没有觉得算法出了什么问题,而且有的情况会超时,怀疑是数组越界,于是翻书,修改声明。

朋友的建议下使用long long.

之后选择查找的算法,使用三分查找

修改后代码如下:

# include <cstdio>
# include <cmath>
# include <algorithm>
using namespace std;
const int N = 2e4 + 12;
int n;
long long t,m = 0x7fffffff,y[N];
long long check(long long k)
{
    long long ans = 0;
    for(int i = 1;i <= n;i++)
    ans += abs(y[i] - k);
    return ans;
}
int main()
{
    scanf("%d %lld",&n,&t);
    for(int i = 1;i <= n;i++)
     for(int j = 0;j < 2;j++)
      scanf("%lld",&y[i]);
    sort(y + 1,y + n + 1);
    long long l = y[1],r = y[n],mid1,mid2;
    while(l + 5 < r)
    {
        mid1 = l + (r - l) / 3,
      mid2 = l + (r - l) / 3 * 2;
        if(check(mid1) < check(mid2))r = mid2;
        else l = mid1;
    } 
    for(int i = l;i <= r;i++)m = min(m,check(i));
    printf("%lld\n",m * t);
}

abs函数用来求绝对值,声明改为long long.

AC.

但后续和学长交流得知,当初理解没问题,后续想复杂了。

感想:

1.分析题目第一重要,虽然看着很像查找但最终思路很简单;

2.代码规范,对C++还不熟悉,代码中c与c++杂糅,需要尽快从c转向c++;

3.多刷刷洛谷,不能再一道题做一天了。

最后附上正解(python)? ?(来自学长)

n = eval(input())
t = eval(input())
y_pos = []
y_max = -1
y_min = 100000000
distance = 100000000
for i in range(n):
    temp = input()
    temp = int(temp.split(" ")[1])
    y_pos.append(temp)
    if(temp > y_max):
        y_max = temp
    if(temp < y_min):
        y_min = temp
for i in range(y_min, y_max+1):
    temp = 0
    No = 0
    for j in range(n):
        temp += t*abs(y_pos[j]-i)
    if(temp < distance):
        distance = temp
print(distance)

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-31 15:16:03  更:2021-08-31 15:17:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 21:07:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计