《程序设计思维与实践》 week3 —— 作业题

A — 选数问题 (DFS解题)

题目描述

Given n positive numbers, ZJM can select exactly K of them that sums to S. Now ZJM wonders how many ways to get it!
译文:从n个数中选K个,使得他们的和为S;

Input

The first line, an integer T<=100, indicates the number of test cases. For each case, there are two lines. The first line, three integers indicate n, K and S. The second line, n integers indicate the positive numbers.
译文:第一行输入T (<= 100),代表数据的总组数;对于每一组,其输入包括两行;第一行输入n,K,S,第二行,n个数据;

Output

For each case, an integer indicate the answer in a independent line.
译文:对于每一组数据,其结果在单独的一行中;

Sample Input

1
10 3 10
1 2 3 4 5 6 7 8 9 10

Sample Output

4

解题思路

vector< int > elements 用于存储输入的数;
list< int > e 用于存储选择的数;

DFS的过程就相当于是将所有的n个数进行组合,选择其中的K个进行求和;
参数
int i — 所选数字在elements数组中的位置;
int sum —— 已选择数字的和;
list < int > e —— 存储选择的数;

在DFS过程中可以直接舍去的方案:

1、当选择的数超过n个的时候;
2、所选数字的和超过了S;
3、所选数字的个数超过了K;

解题代码

#include <iostream>
#include <vector>
#include <list>
#include <cmath>
using namespace std;

int T;
int n, K, S;
int solutions = 0;
int element;
vector<int> elements;
list<int> e;

void dfs(int i, int sum, list<int> e) {
    if (sum == S && e.size() == K) {
        solutions++;
        return;
    }
    if (i >= n) {return;}
    if (sum > S || e.size() > K) {return;}
    solve(i + 1, sum, e);
    
    e.push_back(elements[i]);
    solve(i + 1, sum + elements[i], e);
    
    e.pop_back();
    
}

int main()
{
    cin>>T;
    for (int a = 0; a < T; a++) {
        cin>>n>>K>>S;
        for (int b = 0; b < n; b++) {
            cin>>element;
            elements.push_back(element);
        }
        dfs(0, 0, e);
        cout<<solutions<<endl;
        elements.clear();
        e.clear();
        solutions = 0;
    }
}

B — 区间选点 (贪心算法)

题目描述

数轴上有 n 个闭区间 [a_i, b_i]。取尽量少的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)

Input

第一行1个整数N(N<=100)
第2~N+1行,每行两个整数a,b(a,b<=100)

Output

一个整数,代表选点的数目

Sample Input

2
1 5
4 6

Sample Output

1

解题思路

核心

对于一个区间[ a_i,b_i ],其右端点b_i 能够表示这一整个区间,所以在选择“在区间里面的点”时,应该是默认选择右端点b_i,这样能够使得每个区间内都至少有一个点;

存储区间信息

自定义结构体interval包括一个区间的左右端点;
定义vector数组 vector< interval > i储存所有的区间,全部的区间信息录入之后,按照右节点从小到大的顺序进行排列;

存储所选择的点

定义vector数组 vector< int > j
j [0]一定是所有区间里面,右节点最小的那个,即 i [0]. f;
从i [1]开始进行循环,用int型变量 point 表示目前最大的所选择的点,当且仅当 point < i [n]. s,将这个端点值插入j 中,因为point 如果小于了一个区间的左端点,就代表目前选择的点不能保证每个区间里面都有一个点;

输出结果

选择的点都存储在 j 中,那么所求结果即为 j 的容量的大小;

解题代码

#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
#include <cmath>
using namespace std;

int N;
int a, b;
long int pointn;
int symbol;

struct interval {
    int s;
    int f;
};

bool PX(interval x, interval y){
    if (x.f == y.f) {return x.s > y.s;}
    return x.f < y.f;
    
}

vector<interval> i;
vector<int> j;


int main()
{
    cin>>N;
    interval c;
    for (int n = 0; n < N; n++) {
        cin>>a>>b;
        c.s = a;
        c.f = b;
        i.push_back(c);
    }
    sort(i.begin(), i.end(), PX);
    j.push_back(i[0].f);
    int point = i[0].f;
    for (int n = 1; n < N; n++) {
        if (point < i[n].s) {
            point = i[n].f;
            j.push_back(i[n].f);
        }
    }
    pointn = j.size();
    cout<<pointn<<endl;
}

C — 区间覆盖

题目描述

数轴上有 n (1<=n<=25000)个闭区间 [ai, bi],选择尽量少的区间覆盖一条指定线段 [1, t]( 1<=t<=1,000,000)。
覆盖整点,即(1,2)+(3,4)可以覆盖(1,4)。
不可能办到输出-1

Input

第一行:N和T
第二行至N+1行: 每一行一个闭区间。

Output

选择的区间的数目,不可能办到输出-1

Sample Input

3 10
1 7
3 6
6 10

Sample Output

2

解题思路

预处理

1、自定义结构体 interval : 包含左端点( int left ) 和右端点( int right );
2、输入数据: 不在目标区间[ 1, T ]内的,直接舍弃;仅有部分在的,例如仅有右边部分在目标区间内,将左端点置为1、仅有左边部分在的,将右端点置为T;
**3、vector< interval > t: ** 用于储存所有的区间;

排序

按照左端点由大到小排序,当左端点大小相等时,依据右端点从大到小排列;

求解过程

由所规定的排序规则可以得到,t [ 0 ] 一定是所有区间里面,左端点是1的区间长度最大的区间;
往后遍历其余的所有区间,满足如下几种条件的区间应该被选取:(用interval y储存最新被选取的区间)
**1、区间的左顶点 <= y. left && 区间右顶点 > y.right **: 选择该区间能够让总区间往前延伸,但是有一部分是与已选区间发生了重合;
2、区间的左顶点 == y.right + 1: 选择该区间能够往前延伸,且没有重合的部分;
选择的依据: 根据能够往前延伸的长度;对于情况1: L = 区间右顶点 - y. right;对于情况2:
L = 区间右顶点 - 区间左顶点 + 1;对于所有的选择,都是选择两种情况中最大的那个区间;

解题代码

#include <iostream>
#include <vector>
#include <list>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;

int N, T;
int a, b;

struct interval {
    int left;
    int right;
};

bool PX(interval x, interval y) {
    if (x.left == y.left) {return x.right > y.right;}
    return x.left < y.left;
}

vector<interval> t;

int main()
{
    cin>>N>>T;
    interval x;
    int intervaln = 1;
    for (int w = 0; w < N; w++) {
        scanf("%d %d", &a, &b);
        if (b < 1 || a > T) {
            continue;
        }
        else {
            if (a < 1) {a = 1;}
            if (b > T) {b = T;}
            x.left = a; x.right = b;
            t.push_back(x);
        }
    }
    if (t.size() == 0) {
        cout<<-1<<endl;
        return 0;
    }
    
    sort(t.begin(), t.end(), PX);
    
    //无法到达起点 1
    if (t[0].left > 1) {
        cout<<-1<<endl;
        return 0;
    }
    
    interval y = t[0];
    int chosen = 0;
    while (y.right < T) {
        int maxL = 0;
        for (int w = chosen + 1; w < N; w++) {
            if (t[w].left <= y.right && t[w].right > y.right) {
                int L =  t[w].right - y.right;
                if (L > maxL) {
                    maxL = L;
                    chosen = w;
                }
            }
            if (t[w].left == y.right + 1) {
                int L = t[w].right - t[w].left + 1;
                if (L > maxL) {
                    maxL = L;
                    chosen = w;
                }
            }
            
            else
                continue;
        }
        if (maxL == 0) {
            cout<<-1<<endl;
            return 0;
        }
        y = t[chosen];
        intervaln++;
    }
    cout<<intervaln<<endl;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值