Programming thinking assignment week3

Programming thinking assignment week3

The main practice content this week is the greedy algorithm, mainly to find the greedy criterion. Overall, the first two questions were very smooth. Each question was about 20 minutes. The third question spent more time in reducing complexity.

Problem A

Given N positive numbers, you should select K of them that sum to S. Now please calculate how many ways to get it!

1.sample input and output

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.

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

Output

For each case, an integer indicate the answer in a independent line.

4

2. The overall idea and code

Iterate through the input array, with two options for each element: select and unselect. If selected, subtract the element from the difference with the target sum and then look at the next element. If not selected, go directly to the next element. Among them, the timely termination condition (feasibility pruning) is that the difference from the target sum is less than 0, or the number of selected numbers exceeds K but the target and S are not yet reached.

#include<iostream>
#include<algorithm>
using namespace std;

int tmp;
int n,m,K,S;
int *p;
void SOL(int i,int size,int sum)
{
    //符合K个数相加等于S的要求
    if(sum==0&&size==K)
    {
        tmp++;
        return ;
    }
    //提前结束情况
    if(sum<0||size>K||i>=m)
        return ;
    //如果选第i个数
    SOL(i+1,size+1,sum-p[i]);
    //不选
    SOL(i+1,size,sum);
}

int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        tmp=0;
        //一共m个数,K个数的和为S的方案个数
        cin>>m;
        cin>>K;
        cin>>S;
        p=new int[m];
        for(int j=0;j<m;j++)
        {
            cin>>p[j];
        }
        SOL(0,0,S);
        cout<<tmp<<endl;
    }
}

Problem B Interval point selection problem

There are n closed intervals [a_i, b_i] on the number line. Take as few points as possible so that there is at least one point in each interval (the points contained in different intervals can be the same)

1.sample input and output

Input

1 integer N in the first line (N <= 100)
Line 2 ~ N + 1, two integers a, b in each line (a, b <= 100)

2
1 5
4 6

Output

An integer representing the number of points selected

1

2. The overall idea and code

Classic greedy problem. First sort the input interval from the right end point from small to large, and use lim to record the right end point value of the currently selected section. Then traverse the interval array, if the lim point is in the current interval, continue to the next interval. If not, assign the right end of the interval to lim, and select the interval number ++.

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

class section
{
public:
    section()
    {
        _a=0;
        _b=0;
    }
    section(int a,int b)
    {
        _a=a;
        _b=b;
    }
    inline bool operator < ( section & x)
    {
        return _b<x._b;
    }
public:
    int _a,_b;
};

bool cmp(section a,section b)
{
    return a._b<b._b;
}

int n;
vector<section> p;
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int a,b;
        cin>>a;
        cin>>b;
        section Nsection(a,b);
        p.push_back(Nsection);
    }
    sort(p.begin(),p.begin()+n,cmp);
    int lim=p.front()._b;
    int tmp=1;
    for(int i=1;i<n;i++)
    {
        if(lim>=p[i]._a&&lim<=p[i]._b)
            continue;
        else
        {
            tmp++;
            lim=p[i]._b;
        }
    }
    cout<<tmp<<endl;
    return 0;
}

Problem C Interval coverage problem

There are n (1 <= n <= 25000) closed intervals [ai, bi] on the number line. Choose as few intervals as possible to cover a specified line segment [1, t] (1 <= t <= 1,000,000).
Cover the whole point, ie (1,2) + (3,4) can cover (1,4).
Impossible to do output -1

1.sample input and output

Input

The first line: the
second line of N and T to the N + 1 line: each line has a closed interval.

3 10
1 7
3 6
6 10

Output

The number of selected intervals cannot be output -1

2

2. The overall idea and code

For the greedy problem, first go to a mind map for solving the problem.
Question C submission process

In terms of idea design, first sort the input interval array according to the right end point. Use mlim to record the rightmost endpoint value of the currently selected interval, and pos to record the position of the currently selected interval in the array. Each time the count function is called, the array will be traversed from pos to the beginning, select the range starting from milm and the right end value is the largest, assign the new right end value to Mlim, and record pos. Until it reaches the target right endpoint value t. Among them, the situation that cannot be achieved is that there is an uncoverable empty point between the intervals (indicated in the code that Mlim is not assigned a new value), and the maximum right endpoint cannot reach the target value t (in the code, start is equal to Mlim ).
The final code complexity is O (nlogn)

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

class section
{
public:
    section()
    {
        _a=0;
        _b=0;
    }
    section(int a,int b)
    {
        _a=a;
        _b=b;
    }
public:
    int _a,_b;
};

int n;//区间个数
int t;//目标右端点值
int wa=-1;//错误输出
int tmp=1;//区间个数计数
vector<section> p;//区间数组

bool cmp(section a,section b)
{
    return a._b<b._b;
}

void count(int s,int start)
{
    //记录从start开始的区间能够到达的最右点
    int Mlim=0;
    //记录下一次数组遍历的起始位置
    int pos=0;
    //判断是否成功结束
    if(start==t)
    {
        cout<<tmp;
        return;
    }
    //简化区间到【start,t】之中
    for(int i=s+1;i<p.size();i++)
    {
        if(p[i]._a<=start+1)
        {
            //p[i]._a = start;
            if(p[i]._b>Mlim)
            {
                Mlim = p[i]._b;
                pos=i;
            }
        }
    }
    if(Mlim==0||Mlim==start)
    {
        cout<<wa;
        return ;
    }
    else {
        tmp++;
        //cout<<Mlim<<endl;
        count(pos,Mlim);
    }
}

int main()
{
    while(cin>>n)
    {
        scanf("%d", &t);
        //记录从1起始的区间能够到达的右极点
        tmp=1;
        int mlim = 0;
        for (int i = 0; i < n; i++) {
            int a, b;
            scanf("%d", &a);
            scanf("%d", &b);
            if (b >= t) {
                b = t;
            }
            if (a <= 1) {
                a = 1;
                if (b > mlim)
                    mlim = b;
            }
            section Nsection(a, b);
            p.push_back(Nsection);
        }
        if (mlim == 0) {
            cout << wa;
            return 0;
        }
        //按右端点排序
        sort(p.begin(), p.begin() + p.size(), cmp);
        count(0, mlim);
        p.clear();
    }
    return 0;
}
Published 8 original articles · Likes2 · Visits 252

Guess you like

Origin blog.csdn.net/lawrenceY/article/details/104761358