Projeto e análise de algoritmo - algoritmo guloso (atualização contínua ...)
O conceito de algoritmo guloso:
independentemente da solução ótima geral, cada etapa é encontrar a solução ótima atual primeiro, eu só me importo com a solução ótima atual, a primeira etapa é a melhor, a segunda etapa é a melhor e o todo é também o melhor no final.! Claro, esse algoritmo também tem suas limitações.Para alguns problemas, cada etapa é ótima e pode não ser ótima como um todo.
Um exemplo que não se resolve com a ganância :
os passos da solução:
Questão um, organização do evento:
Descrição do problema:
Cada uma das n atividades tem um horário de início se um horário de término f. Quando uma atividade está em andamento, outras atividades não podem ser realizadas durante este período de tempo [s, f). Resolva o arranjo ideal do plano de atividades para fazer uso do tempo A taxa mais alta, ou seja, o tempo total de atividades de agendamento / (max_f-min_s);
entrada:
entrada n é o número de atividades, e cada uma das próximas n linhas insere
a hora de início da atividade e o horário de término da atividade. O
plano de arranjo ideal é usado
Saída de maximização de tempo :
saída do
tempo ocupado pelo plano de arranjo ideal / tempo total
e o plano de arranjo de atividade (produto n 0 ou 1, 1 significa arranjo, 0 significa nenhum arranjo);
input_case:
11
1 4
3 5
0 6
5 7
3 8
5 9
6 10
8 11
8 12
2 13
12 14
output_case:
10/14
1 0 0 1 0 0 0 1 0 0 1
Idéia:
Primeiro organize de acordo com f de pequeno a grande, primeiro organize a atividade com o menor f, calcule agora = f, então encontre s_i> = now, se s_i> = now,
organize a atividade e atribua agora a i, encontre o último problema por sua vez e resolvê-lo;
código:
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef struct Node{
int s;
int f;
int isok;
}Act;
bool cmp(Act a,Act b){
return a.f<b.f;
}
void f(Act *a,int n){
a[0].isok=1;
int j=0;
for(int i=1;i<n;i++){
if(a[i].s>=a[j].f){
a[i].isok=1;
j=i;
}else{
a[i].isok=0;
}
}
return ;
}
int main(){
int n;
scanf("%d",&n);
Act a[n];
for(int i=0;i<n;i++){
scanf("%d %d",&a[i].s,&a[i].f);
a[i].isok=0;
}
sort(a,a+n,cmp);//需要对结构体数组排序,按f从小到大的顺序排序
f(a,n);
int sum=0;
int min_s=a[0].s;
int max_f=a[0].f;
for(int i=0;i<n;i++){
if(a[i].isok==1){
sum+=a[i].f-a[i].s;
}
if(a[i].s<min_s){
min_s=a[i].s;
}
if(max_f<a[i].f){
max_f=a[i].f;
}
}
printf("%d/%d\n",sum,max_f-min_s);
for(int i=0;i<n;i++){
printf("%d",a[i].isok);
if(i<n-1)printf(" ");
}
return 0;
}
Problema dois, problema de carregamento ideal
Descrição do problema:
n contêineres são carregados em um navio com uma carga de c, 1 é carregado, 0 não é carregado e quantas caixas podem ser carregadas no máximo (sem considerar a questão de espaço).
Cada caixa tem seu próprio peso e número;
entrada:
insira um inteiro positivo n e um inteiro positivo c, respectivamente representando o número de caixas de carga e a carga do navio; a
próxima linha insere n inteiros positivos para representar o peso de n contêineres ;
Ouput: produz
o grau de carregamento ideal:
o número de caixas carregadas / o número total de caixas
exibe o status de carregamento de cada caixa:
(de acordo com o número da caixa 1-n, produz uma string de 0 ou 1, separada por espaços, 1 é carregado, 0 não é Carregar)
input_case:
5 6
1 4 3 2 6
output_case:
最大装载度:
3/5
编号1-n的装载情况:
1 0 1 1 0
Idéia:
Organizar de acordo com o peso do pequeno ao grande, e carregá-los em ordem até que não possam mais ser instalados, ou seja, a quantidade pode ser maximizada de acordo com o princípio do isqueiro primeiro.
código:
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef struct elem{
int x; //编号
int weight;//重量
int isok; //是否被装入,0为不装入,1为转入;
}elem;
bool cmp_weight(elem e1,elem e2){
return e1.weight<e2.weight;
}
bool cmp_x(elem e1,elem e2){
return e1.x<e2.x;
}
int main(){
int n,c;
scanf("%d %d",&n,&c);
elem a[n];
for(int i=0;i<n;i++){
scanf("%d",&a[i].weight);
a[i].isok=0;
a[i].x=i+1;
}
sort(a,a+n,cmp_weight);//按重量从小到大排好
int sum=0;
int i;
for(i=0;i<n&&sum<=c;i++){
sum+=a[i].weight;//轻者优先
a[i].isok=1;
}
if(sum>c){
//退一步,以满足题意
a[i-1].isok=0;
sum-=a[i-1].weight;
}
int sum_isok=0;
for(int i=0;i<n;i++){
if(a[i].isok==1){
sum_isok++;
}
}
sort(a,a+n,cmp_x);//最后再按编号从小到大排好
printf("最大装载度:\n%d/%d\n",sum_isok,n);
printf("编号1-n的装载情况:\n");
for(int i=0;i<n;i++){
printf("%d",a[i].isok);
if(i<n-1)printf(" ");
}
return 0;
}
Problema três, problema de caminho mais curto de fonte única (algoritmo dijkstra)
Descrição do problema:
Para o gráfico direcionado ponderado G (V, E), encontre o comprimento do caminho mais curto do ponto a ao ponto b e dê saída -1 se ele não puder ir;
entrada:
insira quatro inteiros positivos:
nm aa bb
representa o número de nós, o número de arestas, o ponto inicial e o ponto final; as
próximas m linhas inserem cada linha de entrada: ii jj len
é a distância do nó ii até node jj len;
output:
Se não houver maneira de ir de aa para bb, output: de jeito nenhum! \ nSe
houver o caminho mais curto, imprima o comprimento do caminho mais curto: minlen way:% d \ n
input_case:
7 10 1 7
1 2 1
1 3 3
2 3 4
2 5 2
3 4 6
3 6 2
4 6 5
4 5 1
5 7 4
6 7 4
output_case:
minlen way:7
código:
#include<stdio.h>
#define SIZE 99
#define INF 9999999
int M[SIZE][SIZE];
int main(){
int n,m;
int aa,bb;
scanf("%d %d",&n,&m);
scanf("%d %d",&aa,&bb);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
M[i][j]=INF;
}
}
int ii,jj,len;
for(int i=0;i<m;i++){
scanf("%d %d %d",&ii,&jj,&len);
M[ii][jj]=len;
}
int sum=0;
int isput[n+1]={
0};
int prim[n+1]={
0};
for(int i=1;i<=n;i++){
prim[i]=M[aa][i];
}
prim[aa]=0;
isput[aa]=1;
prim[0]=INF;
int flag=0;
while(1){
int j=0;
for(int i=1;i<=n;i++){
if(prim[i]<prim[j]&&isput[i]==0){
j=i;
}
}
if(j==0){
flag=0;
break;
}
isput[j]=1;
if(j==bb){
flag=1;
break;
}
for(int i=1;i<=n;i++){
if(isput[i]==0&&M[j][i]+prim[j]<prim[i]){
prim[i]=M[j][i]+prim[j];
}
}
}
if(flag==0){
printf("no way!\n");
}else{
printf("minlen way:%d\n",prim[bb]);
}
return 0;
}
Problema quatro, problema de spanning tree mínimo (algoritmo prim)
O problema é apresentado:
há n nós, como construir uma estrada, fazer cada nó conectado (formar um grafo conectado) e minimizar o custo da estrada;
aqui para simplificar o problema, discuta apenas o grafo não direcionado!
entrada:
insira um número inteiro positivo n, m
representam respectivamente o número de nós e o número de estradas.
A entrada aa, bb e len em cada linha das próximas m linhas
são o ponto inicial, o ponto final e o comprimento de a estrada respectivamente;
saída:
saída o custo mínimo de construção de uma estrada (ver exemplo)
! Se a saída não pode ser conectado nenhuma maneira
input_case:
6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3
output_case:
min pay:12
código:
//prim算法
#include<stdio.h>
#define INF 99999
#define SIZE 99
int M[SIZE][SIZE];
int main(){
int n,m;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
M[i][j]=INF;
}
}
int aa,bb,len;
for(int i=0;i<m;i++){
scanf("%d %d %d",&aa,&bb,&len);
M[aa][bb]=len;
M[bb][aa]=len;
}
int dist[n+1]={
0};
int put[n+1]={
0};
for(int i=1;i<=n;i++){
dist[i]=M[1][i];
}
dist[1]=0;
put[1]=1;
dist[0]=INF;
int sum=0;
while(1){
int j=0;
for(int i=1;i<=n;i++){
if(dist[i]<dist[j]&&put[i]==0){
j=i;
}
}
if(j==0)break;
sum+=dist[j];
put[j]=1;
for(int i=1;i<=n;i++){
if(dist[i]>M[i][j]){
dist[i]=M[i][j];
}
}
}
int flag=0;
for(int i=1;i<=n;i++){
if(put[i]==0){
flag=1;
break;
}
}
if(flag==1){
printf("no way!\n");
}else{
printf("min pay:%d\n",sum);
}
return 0;
}