Semana de atribuição do pensamento de programação3

Semana de atribuição do pensamento de programação3

O principal conteúdo prático desta semana é o algoritmo ganancioso, principalmente para encontrar o critério ganancioso. No geral, as duas primeiras perguntas foram muito suaves, cada pergunta durou cerca de 20 minutos e a terceira passou mais tempo reduzindo a complexidade.

Problema A

Dados N números positivos, você deve selecionar K deles que somam S. Agora calcule quantas maneiras de obtê-lo!

1. entrada e saída de amostra

Entrada

A primeira linha, um número inteiro T <= 100, indica o número de casos de teste. Para cada caso, há duas linhas. A primeira linha, três números inteiros, indica n, K e S. A segunda linha, números inteiros, indica os números positivos.

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

Resultado

Para cada caso, um número inteiro indica a resposta em uma linha independente.

4

2. A idéia e o código gerais

Faça uma iteração na matriz de entrada, com duas opções para cada elemento: selecione e desmarque. Se selecionado, subtraia o elemento da diferença com a soma de destino e, em seguida, observe o próximo elemento. Se não selecionado, vá diretamente para o próximo elemento. Entre eles, a condição de finalização oportuna (remoção de viabilidade) é que a diferença da soma da meta é menor que 0 ou o número de números selecionados excede K, mas a meta e S ainda não foram atingidas.

#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;
    }
}

Problema B Problema de seleção do ponto de intervalo

Existem n intervalos fechados [a_i, b_i] na linha numérica. Pegue o mínimo de pontos possível para que haja pelo menos um ponto em cada intervalo (os pontos contidos em diferentes intervalos podem ser os mesmos)

1. entrada e saída de amostra

Entrada

1 número inteiro N na primeira linha (N <= 100)
Linha 2 ~ N + 1, dois números inteiros a, b em cada linha (a, b <= 100)

2
1 5
4 6

Resultado

Um número inteiro representando o número de pontos selecionados

1

2. A idéia e o código gerais

Problema ganancioso clássico. Primeiro, classifique o intervalo de entrada do ponto final direito de pequeno a grande e use lim para registrar o valor do ponto final direito da seção atualmente selecionada. Em seguida, percorra a matriz de intervalos, se o ponto limite estiver no intervalo atual, continue no próximo intervalo. Caso contrário, atribua a extremidade direita do intervalo a lim e selecione o número do intervalo ++.

#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;
}

Problema C Problema na cobertura do intervalo

Existem n (1 <= n <= 25000) intervalos fechados [ai, bi] na linha numérica Escolha o menor número possível de intervalos para cobrir um segmento de linha especificado [1, t] (1 <= t <= 1.000.000).
Cubra todo o ponto, ou seja, (1,2) + (3,4) pode cobrir (1,4).
Impossível fazer saída -1

1. entrada e saída de amostra

Entrada

A primeira linha: a
segunda linha de N e T para a linha N + 1: cada linha tem um intervalo fechado.

3 10
1 7
3 6
6 10

Resultado

O número de intervalos selecionados não pode ser emitido -1

2

2. A idéia e o código gerais

Para o problema ganancioso, primeiro vá a um mapa mental para resolvê-lo.
Processo de envio da pergunta C

Em termos de design de ideias, primeiro classifique a matriz do intervalo de entrada de acordo com o ponto final correto. Use mlim para registrar o valor do ponto final mais à direita do intervalo atualmente selecionado e pos para registrar a posição do intervalo atualmente selecionado na matriz. Cada vez que a função de contagem é chamada, a matriz será percorrida da posição até o início, selecione o intervalo que começa em milm e o valor final direito é o maior, atribua o novo valor final direito a Mlim e registre pos. Até atingir o valor-alvo correto do ponto final t. Entre eles, a situação que não pode ser alcançada é a de que existe um ponto vazio descoberto entre os intervalos (indicado no código que Mlim não recebeu um novo valor) e o ponto final máximo direito não pode atingir o valor-alvo t (no código, start é igual a Mlim )
A complexidade final do código é 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;
}
Publicado 8 artigos originais · Curtidas2 · Visitas 252

Acho que você gosta

Origin blog.csdn.net/lawrenceY/article/details/104761358
Recomendado
Clasificación