Projeto e análise de algoritmos --- algoritmo ganancioso

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 :
Insira a descrição da imagem aqui
os passos da solução:
Insira a descrição da imagem aqui

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

Acho que você gosta

Origin blog.csdn.net/timelessx_x/article/details/115053106
Recomendado
Clasificación