程序设计思维与实践 Week3 作业

A-选数问题

题意:
n个数中选K个数,其和等于S的方案有多少个?
思路:
该题是典型的子集枚举问题,但需要对过程进行剪枝。当选数个数大于k或者总和大于s时,就不需要继续进行。枚举过程采用dfs方法。
总结:
采用dfs方法进行搜索,并在过程中合理的剪枝,顺利解决问题。
代码:

#include <iostream>
#include <vector>
using std::vector;
int count, n, k, s;
int* num;
vector<int> res;
void solve(int sum, int cur)
{
	if (res.size() == k && sum == 0)
	{
        count++;
        return;
    }
	if (cur >= n || res.size() > k || sum < 0)
		return;
	solve(sum, cur + 1);
	res.push_back(num[cur]);
	solve(sum - num[cur], cur + 1);
	res.pop_back();
}
int main()
{
	int m;
    scanf("%d", &m);
    for (int i = 0; i < m;i++)
    {
		count = 0;
        scanf("%d%d%d", &n, &k, &s);
		num = new int[n];
		for (int j = 0; j < n; j++)
		{
			scanf("%d",&num[j]);
		}
		solve(s, 0);
        printf("%d\n", count);
    }
	delete[] num;
    //system("pause");
}

B-区间选点

题意:
数轴上有 n 个闭区间 [a_i, b_i]。取尽量少的点,使得每个区间内都至少有一个点。
思路:
上课学长讲了思路。。。利用结构体存储区间的左右端点。在数轴上,从左到右对n个区间依次进行判断,如果两个区间有重叠部分,则点的个数不用增加,但需要修改区间端点的值。反之,增加点的个数即可。
总结:
典型的贪心问题,先对区间进行排序,之后计数,更改区间范围,即可解决问题。
代码:

#include <iostream>
#include <algorithm>
using std::min;
using std::sort;
struct node
{
    int x, y;
} a[1001];
//升序
bool cmp(node a, node b)
{
    return a.x < b.x;
}
int main()
{
    int n;
    while (scanf("%d", &n) == 1)
    {
        for (int i = 0; i < n; i++)
            scanf("%d%d", &a[i].x, &a[i].y);
        sort(a, a + n, cmp);
        int count = 1;
        for (int i = 0; i < n; i++) //计数,更改区间范围
        {
            if (a[i].y < a[i + 1].x)
                count++;
            else
                a[i + 1].y = min(a[i].y, a[i + 1].y);
        }
        printf("%d/n", count);
    }
    //system("pause");
}

C-区间覆盖

题意:
数轴上有 n (1<=n<=25000)个闭区间 [ai, bi],选择尽量少的区间覆盖一条指定线段 [1, t] (1<=t<=1,000,000)。
思路:
上课学长也讲了思路。。。我选择的是从右向左贪心。

  1. 首先利用结构体数组存储区间左右端点。
  2. 在贪心过程:首先选择符合要求的右端点,在这些区间中选择最小的左端点,进而得到一个区间,并修改要求中的右端点。值得一提的是,因为这句话的提醒

(1,2)+(3,4)可以覆盖(1,4)。

对于指定线段[1,t],在过程中我们可以选择[3,5],[6,8]这样的并不直接相连的区间。但是我们不能选择[2,x]作为首区间,首区间必须包含1。所以我们需要对左端点进行特判。这是很容易遗漏的点。

总结:
典型的贪心问题。我刚开始做的时候,使用了过多的sort,结果TE了,现在想想根本没必要使用那么多sort,一次sort即可解决问题。
代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
using std::min;
using std::sort;
struct node
{
    int x, y;
} a[25001];
//升序
bool cmp(node a, node b)
{
    return a.y < b.y;
}
int main()
{
    int count = 0;
    int n, t, flag = 1;
    scanf("%d%d", &n, &t);
    for (int i = 0; i < n; i++)
        scanf("%d%d", &a[i].x, &a[i].y);
    sort(a, a + n, cmp); //右端点升序排列
    while (t > 1)
    {
        int m = n - 1;
        int cnt = n;
        if (n == 0 || a[n - 1].y < t)
        {
            flag = 0;
            break;
        }
        while (a[n - 1].y > t - 1 && n != 0)
        {
            m = (a[n - 1].x < a[m].x) ? n - 1 : m;
            n--;
        }
        t = (a[m].x == 2) ? 2 : a[m].x - 1; //特判左端点
        count++;
    }
    if (flag == 1)
        printf("%d", count);
    else
        printf("-1");
    //system("pause");
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值