一周拓展课辅导内容

本文介绍了两道编程题目,分别是天然气市场连接问题和熄灯强化版问题。天然气市场问题通过分析得出连接管道长度与连接方式无关,采用贪心策略计算最短长度。熄灯强化版问题使用动态规划求解最少操作次数关闭所有灯。
摘要由CSDN通过智能技术生成

天然气

题目描述

Mary 试图控制成都的天然气市场。
专家已经标示出了最好的天然气井和中转站在成都的地图。现在需要将中转站和天然气井连接
起来。每个中转站必须被连接到正好一个钻油井,反之亦然。
Mary 特别指名,建设的天然气管道必须从某个天然气井开始,向南或者向东建设。
Mary 想知道怎么连接每个天然气井和中转站,使得需要的天然气管道的总长度最小。
在这里插入图片描述

输入输出格式

输入:

第一行为一个正整数 n,表示天然气井的数量(中转站的数量与之相等)。
接下来 n 行,每行两个整数 x_i 和 y_i,表示天然气井的坐标。向东走则 x 坐标增加,向北走
则 y 坐标增加;
再接下来 n 行,每行两个数 x_j 和 y_j,表示中转站的坐标。

输出:

输出共一行包含一个数,表示最短的连接管道长度。

输入输出样例

输入:
3
3 5
1 2
4 3
6 3
5 2
2 1
输出:
9

解题思路:

首先,一开始拿到这个题目,哇!暴力大法师(dfs)骗分!真不戳!
哇!一看到数据,很快啊!必超时!那就用贪心骗分吧!5分?!
还是想一想吧……
首先一找规律,就能够发现,其实怎么连根本就不影响到答案?!
因为题目描述中提到过:
在这里插入图片描述那么就只需要在输入的过程中减去天然气井的X和中转站的Y加上天然气井的Y和中转站的X就行了(数组都不用开,我也是fo了)
附上代码:

#include <iostream>
#include <cstdio>

using namespace std;

long long Ans;

int main() {
	int N;
	scanf ("%d", &N);
	for (int i = 1, x, y; i <= N; ++ i)scanf ("%d %d", &x, &y), Ans = Ans - x + y;
	for (int i = 1, x, y; i <= N; ++ i)scanf ("%d %d", &x, &y), Ans = Ans + x - y;
	printf ("%lld\n", Ans);
}

熄灯强化版

题目描述

现有一排数量为K(4≤K≤25)的灯,其中有些打开,有些关闭。
在此初始配置中,不会出现连续的四个灯(包括四个以上)亮起的情况。
你可以将某些熄灭的灯打开,每当四个或更多连续的灯被打开时,该连续块中的灯将自动关闭。
为了使所有K盏灯都关闭,您需要打开的最少灯数是多少?

输入输出格式

输入:
输入的第一行将由整数K组成,表示灯光的数量。 接下来的K行中的每行将有整数0(表示熄灭的灯)或整数1(表示打开的灯)。

输出:
使得所有等都熄灭的最少操作次数

输入输出样例

输入
5
1
1
0
1
1
输出
1

解题思路

这道题目一眼就能看出是dp,但是dp思路是什么呢?
先将每一个连续的亮着的灯的左右边界求出来(左闭右开方便计算长度)
for循环反着来,F[i]表示的状态是第Total个连续的灯到第i个连续的灯的要全部关掉所需要的最少步数
有两种关法:
1.Itself:自己关,不与其它的连续的灯一起关,步数等于4 - 它本身的长度
2.连续:和别的灯一起关
所以看代码:

#include <iostream>
#include <cstdio>
const int MaxN = 35;

using namespace std;

struct On{
	int L,R;
};

On Tot[MaxN];
int Lights[MaxN];
int F[MaxN];
int Total;
int N;

int main() {
	scanf ("%d", &N);
	for (int i = 1; i <= N; ++ i)scanf ("%d", &Lights[i]);
	for (int i = 1, Flag = 0; i <= N + 1; ++ i) {
		if (Flag && Lights[i] == 0)Tot[Total].R = i, Flag = 0;
		else if (! Flag && Lights[i])Tot[++ Total].L = i, Flag = 1;//找到连续开着的灯的左右端点
	}
	for (int i = Total, Con; i >= 1; -- i) {
		Con = Tot[i].R - Tot[i].L;//Con记录有多少个灯是开着的
		F[i] = 4 - Con + F[i + 1];//先初始化为itself
		for (int j = i + 1; j <= Total; ++ j) {//和后面的灯一起关
			if (Tot[j].R - Tot[i].L >= 8)break ;//>=8是不可能一起关掉的
			if (Tot[j].R - Tot[i].L == 7 && Lights[Tot[i].L + 3])break ;
			if (Tot[j].R - Tot[i].L == 6 && Lights[Tot[i].L + 2] == 1 && Lights[Tot[i].L + 3] == 1)break ;//这两种情况也是不能够关掉的
			Con = Con + Tot[j].R - Tot[j].L;
			F[i] = min ((max(4, Tot[j].R - Tot[i].L) - Con + F[j + 1]), F[i]);//打擂台
		}
	}
	printf ("%d\n", F[1]);//F[1]就是答案
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值