剑指NOI周末混合训练之水题大狂欢

改造二叉树

题目描述

在计算机科学中,二叉树是每个节点最多有两个子节点的有序树。通常子节点被称作“左孩子”
和“右孩子”。二叉树常被用作二叉搜索树和二叉堆。
我们现在讨论二叉搜索树。什么是二叉搜索树呢?二叉搜索树首先是一棵二叉树。设 key[p]
表示节点 p 上的数值。对于其中的每个节点 p,若其存在左孩子 lch,则 key[p]>key[lch];若其存
在右孩子 rch,则 key[p]<key[rch]。注意,应该是所有的左子树中节点的 key 小于当前节点 key,
所有右子树中节点的 key 大于当前节点 key。
对于每个节点,无论如何改变其数值,费用总等于 1.
现在给定一棵二叉树,可以任意修改节点的数值,要求用最小的费用将其变成一棵二叉搜索树。

输入输出格式

输入:
第一行一个整数 N,表示二叉树中的节点数;
第二行 N 个整数,每两个整数之间用一个空格隔开,第 i 个整数 Ai表示第 i 个节点的原始数值;
再接下来第 3 行到第 N+1 行,每行两个整数 fa 和 x,中间用一个空格隔开,第 i+1 行表述的是节点
i 的父节点标号是 fa 及父子关系(x=0 表示节点 i 为节点 fa 的左孩子,x=1 表示节点 i 为节点 fa
的右孩子),标号为 1 的节点一定是二叉树的根。
输出:
输出共一行一个整数,即最小的费用值。

输入输出样例

样例输入:

3
2 2 2
1 0
1 1

样例输出:

2

解题思路

要从最下面开始修改,并不需要真正的去修改权值,因为这道题目权值不管怎么更改都是一样的代价
附上代码:

#include <iostream>
#include <cstdio>

const int MaxN = 1e5 + 5;

using namespace std;

struct tree{
   int Ls,Rs,Data;
}Tree[MaxN];

int N;
int Total;
int Q[MaxN];

void Find(int x) {
   int L = 1, R = Total;
   while (L <= R) {
   	int Mid = (R - L >> 1) + L;
   	if (Q[Mid - 1] < x && x < Q[Mid]) {
   		Q[Mid] = x;
   		break ;
   	}
   	if (x > Q[Mid]) L = Mid + 1;
   	else R = Mid - 1;
   }
}

void Dfs(int Root) {
   if (Tree[Root].Ls) Dfs (Tree[Root].Ls);
   if (Tree[Root].Data > Q[Total])Q[++ Total] = Tree[Root].Data;
   else Find (Tree[Root].Data);
   if (Tree[Root].Rs)Dfs(Tree[Root].Rs);
}

int main() {
   scanf ("%d", &N);
   for (int i = 1; i <= N; ++ i)scanf ("%d", &Tree[i].Data);
   for (int i = 2, x, y; i <= N; ++ i) {
   	scanf ("%d %d", &x, &y);
   	if (y)Tree[x].Rs = i;
   	else Tree[x].Ls = i;
   }
   Q[Total] = -1;
   Dfs(1);
   printf ("%d\n", N - Total);
}

自己理解吧[doge]

回家

题目描述

有 N 头奶牛,Farmer John 想送每头奶牛回家,第 i 头奶牛被送回家的单程时间是 Ti(返回牛圈
的时间也同样为 Ti);如果第 i 头奶牛没有被送回家,那么它每一时刻的花费为 Di;当然被送的这
头奶牛是不会在有花费的;现在 Farmer John 想知道把这 N 头奶牛全部都送回家后,总共的最小花
费是多少。

输入输出格式

输入:
第一行一个整数 N,表示 Farmer John 有 N 头奶牛;
下面 N 行,每行 2 个整数 Ti,Di;
输出:
共一行一个整数,表示 Farmer John 把所有奶牛都送回家之后的最小花费;

输入输出样例

样例输入:

3
100 10
200 10
300 10

样例输出:

8000

解题思路

贪心的思路来排序,唉,没错!就硬贪!
附上代码:

#include <iostream>
#include <cstdio>
#include <algorithm>

const int MaxN = 1e6 + 5;

using namespace std;

struct cow {
	int CostTime;
	int Second_Cost;
	bool operator <(const cow &Y) const {//重载运算符来排序
		return CostTime * Y.Second_Cost < Y.CostTime * Second_Cost;//没有错,就是这样的贪心思路!
	}
}Cow[MaxN];

int N;
long long Num;
long long Ans;

int main() {
	scanf ("%d", &N);
	for (int i = 1; i <= N; ++ i)scanf ("%d %d", &Cow[i].CostTime, &Cow[i].Second_Cost), Num += Cow[i].Second_Cost;//定义Num方便后面计算
	sort (Cow + 1, Cow + N + 1);
	for (int i = 1; i <= N; ++ i) {
		Num -= Cow[i].Second_Cost;//送走的这一只牛不会增加花费
		Ans += Num * Cow[i].CostTime * 2;
	}
	printf ("%lld\n", Ans);
}
/*
3
100 10
200 10
300 10
*/

奶酪加工厂

题目描述

奶牛们收购了一个奶酪工厂。
接下来的 N 个星期里,牛奶价格和劳力价格不断起伏。第 i 周,生产一个单位奶酪需要 Ci 便
士。工厂有一个货栈,保存一个单位奶酪,每周需要 S 便士,这个费用不会变化,货栈十分强大,
可以存无限量的奶酪,而且保证它们不变质。
工厂接到订单,在第 i 周需要交付 Yi 单位的奶酪给委托人,第 i 周刚生产的奶酪,以及之前
的存货,都可以作为产品交付。
请帮奶牛们计算这段时间里完成任务的最小代价。

输入输出格式

输入:
第 1 行输入两个整数 N 和 S;
接下来 N 行,输入 Ci 和 Yi;
输出:
输出共一行一个整数,最少的代价;

输入输出样例

样例输入:

4 5
88 200
89 400
97 300
91 500

样例输出:

126900

解题思路

看看是在之前做好比较有还是现在做比较优
附上代码

#include <iostream>
#include <cstdio>

const int MaxN = 1e4 + 5;

using namespace std;

int N;
long long S;
long long C[MaxN],Y[MaxN];
long long Ans = 0;

int main() {
	scanf ("%d %lld", &N, &S);
	for (int i = 1; i <= N; ++ i) {
		long long MinTotal = 0x7fffffff;
		scanf ("%lld %lld", &C[i], &Y[i]);
		for (int j = 1; j <= i; ++ j) {//比较懒就写成1~i了
			MinTotal = min(MinTotal, Y[i] * C[j] + (i - j) * S * Y[i]);
		}
		Ans += MinTotal;
	}
	printf ("%lld\n", Ans);
}

同学会

题目描述

毕业 25 年以后,我们的主人公开始准备同学聚会。打了无数电话后他终于搞到了所有同学的
地址。他们有些人仍在本城市,但大多数人分散在其他的城市。不过,他发现一个巧合,所有地址
都恰好分散在一条铁路线上。他准备出发邀请但无法决定应该在哪个地方举行宴会。最后他决定选
择一个地点,使大家旅行的花费和最小。
不幸的是,我们的主人公既不擅长数学,也不擅长计算机。他请你帮忙写一个程序,根据他同
学的地址,选择聚会的最佳地点。

输入输出格式

输入:
输入文件的第一行为 N,表示城市个数。
以下 N 行,每一行描述了一个城市的信息。
首先是城市里同学的个数 M(M<1000),紧跟着是这个城市到 Moscow(起点站)的距离 L(L<10000)
(km),最后是城市的名称(0<字符串长度<255)。最后一行描述的总是 Moscow,它在铁路线的一端,
距离为 0。
输出:
聚会地点城市名称和旅行费用(单程),两者之间用一空格隔开。每 km 花费一个卢布。

输入输出样例

样例输入:

5
7 9289 Vladivostok
5 8523 Chabarovsk
3 5184 Irkutsk
8 2213 Yalutorovsk
10 0 Moscow

样例输出:

Yalutorovsk 112125

解题思路

因为数据很小,所以直接暴力枚举安排的地点,然后暴力求出费用最后打擂台
附上代码:

#include <iostream>
#include <cstdio>
#include <cmath>

const int MaxN = 155;

using namespace std;

struct Place {
	string Name;
	int Number;
	int L;
}P[MaxN];

long long MinAns = 0x7fffffff;
string MinPlace;
int N;

int main() {
	scanf ("%d", &N);
	for (int i = 1; i <= N; ++ i) {
		scanf ("%d %d", &P[i].Number, &P[i].L);
		cin >> P[i].Name;
	}
	for (int i = 1; i <= N; ++ i) {//暴力枚举安排地点
		long long Total = 0;
		for (int j = 1; j <= N; ++ j) {
			if (i == j)continue ;
			Total += (abs (P[i].L - P[j].L) * P[j].Number);//暴力求费用
		}
		if (MinAns > Total) {//打擂台
			MinAns = Total;
			MinPlace = P[i].Name;
		}
	}
	cout << MinPlace << ' ' << MinAns;//圆满输出
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值