minhas informações de contato
Correspondência[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
método gananciosoÉ uma espécie de soluçãoProblema de otimização Este método sempre considera a estratégia para alcançar o resultado global ótimo (ou melhor) após o ótimo (ou melhor) local no estado atual. Obviamente, se for adoptada uma estratégia melhor mas não óptima (a estratégia óptima pode não existir ou não ser fácil de pensar), o resultado global obtido não pode ser óptimo.Para obter o resultado ideal, cada estratégia de etapa intermediária deve ser ótima, portanto, o método ganancioso é estritamente usado para resolvê-la.otimizar A questão requer justificação da estratégia adotada. A ideia geral da prova é usar prova por contradição e indução matemática, ou seja, assumir que a estratégia não pode levar à solução ótima, e então obter a contradição por meio de uma série de derivações para provar que a estratégia é ótima e, finalmente, use a indução matemática para garantir o ótimo global. No entanto, para uso diário, pode não ser fácil ou fácil provar rigorosamente a estratégia que vem à mente (a prova da ganância é muitas vezes mais difícil do que a própria ganância), então, de modo geral, se você pensar em uma estratégia que pareça viável, E se você não puder dar um contra-exemplo, seja corajoso o suficiente para implementá-lo.
Dado um número de números de 0 a 9, você pode organizar esses números em qualquer ordem, mas deve usá-los todos e tornar o número de destino o menor possível (é claro, 0 não pode ser o primeiro, por exemplo). dois 0, dois 1, três 5 e um 8, o menor número obtido é 100155858.
Acredito que você pode ver a estratégia imediatamente: primeiro selecione o menor número que não seja 0 de 1 a 9 para gerar e, em seguida, produza os números de 0 a 9. O número de vezes que cada número é gerado é o número restante.
Prova de estratégia correta:
O livro é muito abstrato e parece um pouco errado. Aqui o próprio blogueiro escreveu um:
- #include <cstdio>
- #include <vector>
- #include <iostream>
- #include <algorithm>
- using namespace std;
-
- int main() {
- vector<int> V;
- for(int i=1;i<=10;i++)
- {
- int temp=0;
- cin>>temp;
- V.push_back(temp);
- }
- sort(V.begin(),V.end()); //直接排成升序
- int flag=0; //标记
- for(int i=0;i<=9;i++)
- if(V[i]!=0)
- {
- int temp=V[i];
- V[i]=V[0];
- V[0]=temp;
- flag=i;//保存第一个不为0的位置
- break;
- }
- for(int i=flag+1;i<=9;i++) //找更小的头,直接从flag下一位开始即可,节省时间~
- if(V[i]<V[0]&&V[i]!=0)
- {
- int temp=V[i];
- V[i]=V[0];
- V[0]=temp;
- }
- for(int i=0;i<=9;i++)
- cout<<V[i];
- }
Logicamente não é difícil, o principal é pensar com clareza~
Imagine se você fosse o chefe, como seria “ganancioso”? Obviamente - se você só precisasse vender o maior número possível de mooncakes com o preço unitário mais caro possível dentro da demanda limitada, não seria possível obter o maior volume de negócios? A seguinte implementação escrita pelo próprio blogueiro é diferente daquela do livro:
- #include <cstdio>
- #include <vector>
- #include <iostream>
- #include <algorithm>
- using namespace std;
-
- struct mooncake{
- double num; //总数
- double income; //总收入
- double price; //单价,需要自己计算
- };
-
- int main() {
- int N,M;
- cin>>N>>M;
- vector<mooncake> V;
- for(int i=1;i<=N;i++)
- {
- mooncake temp;
- V.push_back(temp);
- }
- cout<<"请输入数量:"<<endl;
- for(int i=1;i<=N;i++)
- {
- double num=0;
- cin>>num;
- V[i-1].num=num;
- }
- cout<<"请输入总价:"<<endl;
- for(int i=1;i<=N;i++)
- {
- double income=0;
- cin>>income;
- V[i-1].income=income;
- }
- for(int i=0;i<=N-1;i++)
- V[i].price=V[i].income/V[i].num; //计算单价
- //按单价降序排列!保证贵的尽可能多卖
-
- for(int i=0;i<=V.size()-1;i++)
- {
- for(int j=i;j<=V.size()-1;j++)
- if(V[j].price>V[i].price)
- {
- mooncake temp;
- temp=V[j];
- V[j]=V[i];
- V[i]=temp;
- }
- }
- for(int i=0;i<=V.size()-1;i++)
- cout<<"单价第"<<(i+1)<<"高的值为:"<<V[i].income<<" "<<V[i].price<<" "<<V[i].num<<endl;
-
-
- for(int i=0;i<=N-1;i++)
- cout<<V[i].num<<endl;
- int j=0; //使用的下标
- double count=0; //总利润
- while(M>0) //当还有需求量时
- {
- double doubt=0;
- doubt=M-V[j].num; //用M减去当前类型的额总量
- if(doubt>=0)//减了以后M还有剩余
- {
- M-=V[j].num;//当前种类全部卖出
- count+=V[j].income;//直接总价相加
- j++;
- cout<<V[j].num;
- }
- else if(doubt<0) //不够减这么多
- {
- count+=V[j].price*M;//剩余部分按照单价计算
- break;
- }
- }
- cout<<"最高利润值为:"<<count<<endl;
- return 0;
- }
Experimente com cuidado o loop whlie acima: quando M não for 0 - ou seja, ainda há demanda, venda os mooncakes mais caros. Venda um por um em ordem: Se a demanda atual for suficiente para vender todos os tipos atuais, o preço total será adicionado diretamente, se não for suficiente para vender todos os tipos atuais, então venda tantos quantos houver; são e calculam com base no preço unitário ~
Vamos testá-lo com o caso de teste do livro:
O resultado é 94,50, o que é consistente com a resposta padrão~
Além disso, o blogueiro aqui escreve diretamente a classificação na função principal, escreve-a em uma função independente e depois a chama. Parece haver um bug no vetor do tipo de estrutura e a classificação não é bem-sucedida. razão, você pode escrever na área de comentários ~
A questão central é a seguinte:
Para este tipo de pergunta, você só precisa lembrar——Dê prioridade ao intervalo com o extremo esquerdo maior!
Vamos falar sobre por que fazemos isso, como mostra a imagem acima: não é difícil de encontrar,Para garantir o maior número possível de escolhas, quando um intervalo mais longo contém um intervalo mais curto, devemos selecionar primeiro o intervalo mais curto, Isso é fácil de entender.
Para a situação acima, como intervalos sobrepostos como 1 e 2, não é difícil descobrir que se você selecionar o intervalo 1 com o maior ponto final esquerdo, ele ocupará apenas a posição 9, enquanto se você selecionar o intervalo 2, ele ocupará posição 8. Posição - Isto obviamente não está de acordo com a ideia de gastar o mínimo de dinheiro possível (gastar menos espaço), então você deve escolher o mais à esquerda possível, para que haja mais espaços vazios à direita ~ como acima,Podemos ver pelo cálculo manual que existem no máximo 4 disjuntos.
Código do livro didático:
- #include <cstdio>
- #include <algorithm>
- using namespace std;
-
- const int maxn=110;
- struct Inteval{
- int x,y; //开区间左右端点
- }I[maxn];
-
- bool cmp(Inteval a,Inteval b)
- {
- if(a.x!=b.x)
- return a.x>b.x; //左端点从大到小排序
- else
- return a.y<b.y; //左端点相同的按右端点从小到大排序
- }
-
- int main() {
- int n;
- while(scanf("%d",&n,n!=0))
- {
- for(int i=0;i<n;i++)
- scanf("%d%d",&I[i].x,&I[i].y);
- sort(I,I+n,cmp); //排序区间
- int ans=1,lastX=I[0].x;
- //ans记录总数,lastX记录上一个被选择的区间的左端点
- for(int i=1;i<n;i++)
- {
- if(I[i].y<=lastX) //如果该区间右端点在lastX左边
- {
- lastX=I[i].x; //以I[i]作为新选中的区间
- ans++; //不相交的区间个数+1
- }
- }
- printf("%dn",ans);
- }
- return 0;
- }
No entanto, os blogueiros ainda não gostam de arrays originais.
- #include <iostream>
- #include <vector>
- #include <algorithm>
- using namespace std;
-
- struct section{
- int x=0;
- int y=0;
- //x和y分别为左右端点
- };
-
-
- int main() {
- int n=0;
- vector<section> V;
- cin>>n;
- for(int i=1;i<=n;i++) //读入数据
- {
- section temp;
- int x=0,y=0;
- cin>>x>>y;
- if(x>y) //防止左端点大于右端点
- {
- int temp1=x;
- x=y;
- y=temp1;
- }
- else if(x==y) //若左右端点相同
- {
- i-=1; //则当前输入 不算
- cout<<"不可以输入相同的左右端点!"<<endl;
- continue; //舍弃数据,本次循环作废~
- }
- temp.x=x;
- temp.y=y;
- V.push_back(temp);
- }
- //按要求排序区间优先级
- for(int i=0;i<=V.size()-1;i++)
- {
- for(int j=i+1;j<=V.size()-1;j++)
- {
- if(V[j].x>V[i].x) //左端点越大越靠前
- {
- section temp=V[j];
- V[j]=V[i];
- V[i]=temp;
- }
- else if(V[j].x==V[i].x&&V[j].y<V[i].y) //左端点相同的话,右端点小的优先
- {
- section temp=V[j];
- V[j]=V[i];
- V[i]=temp;
- }
- }
- }
- cout<<"顺序如下:"<<endl;
- for(int i=0;i<=V.size()-1;i++)
- cout<<V[i].x<<"~"<<V[i].y<<endl;
- int count=1,lastX=V[0].x;
- //count用来统计总数,lastX是上一个符合条件的区间的左端点
-
- for(int i=1;i<=V.size()-1;i++)//直接从第二个区间开始
- {
- if(V[i].y<lastX) //如果当前区间的右端点不和上一个左端点相加,满足题意
- {
- lastX=V[i].x;
- count++;
- }
- }
- cout<<count<<endl;
- return 0;
- }
O teste é o seguinte:
Em geral, o método guloso é uma ideia algorítmica usada para resolver um tipo de problema de otimização e espera derivar o resultado ótimo global a partir de uma estratégia ótima local.algoritmo ganancioso Os problemas aplicáveis devem satisfazer as propriedades da subestrutura ótima, ou seja, a solução ótima de um problema pode ser efetivamente construída a partir das soluções ótimas de seus subproblemas. Obviamente nem todos os problemas são adequados para o método guloso, mas isso não impede que o algoritmo guloso se torne um algoritmo simples, prático e eficiente.