欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-18 13:42:07
...

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");
}

相关标签: 实验报告