データ構造の三大アルゴリズム(事例分析)

概要

この記事では、データ構造で最も一般的に使用される 3 つのアルゴリズム (分割統治法動的計画法欲張りアルゴリズム)について説明します。主にこれらのアルゴリズムの古典的なケースから始めて、アルゴリズムを分析して理解します。

分割統治

分割統治法は、大きな魚をいくつかの部分に分割し、それぞれの魚を別々に調理してから皿を形成することと一般的に理解できます. つまり、分割統治法は、大きな問題を多くの小さな問題に分割することであり、これらの小さな問題が解決された後、大きな問題全体が解決される可能性があります.処理プロセス中に、これらの小さな問題の処理方法は、違う。次のケースからさらに分析して理解してみましょう。

問題の説明

a[0:n-1]ソートされた配列であると仮定して、配列にない場合は 未満の最大要素位置とより大きい最小要素位置を返すように二分探索アルゴリズムを書き直してください。検索要素が配列内にある場合は、配列内の位置同じです。xxixjijx

アルゴリズム思考と設計

n一連の要素の最大値と最小値をn見つける問題を単純化し、この数を 2 つのグループに分けて、それぞれ最大値と最小値を見つけます。次に、各グループの数が以下になるまで再帰的に分解します2二分探索の考え方を利用して、配列内のキーワードを検索しx配列の先頭と末尾にインデックスを付けますlowtopそのときlow<=topx配列の中央値と等しい場合はx配列にあることを意味し、添え字を返しますi,j;配列の中央値より大きい場合は中央値と等しい;場合found 、 にコピーして に代入し、添え字を返します完全なコードは次のとおりです。xlow+1xtop+1lowtopxtopi,lowji,j

#include<stdio.h>
int search(int a[],int length, int x)
{
    
    
int i = 0, j = 0;
int s= -1;
int top = length - 1;
	int mid = 0;
	int low = 0;
	while (low <= top)
	{
    
    
		mid = (low + top) / 2;
		if (a[mid] == x)
		{
    
    
			s = mid;
		}
		if (a[mid] < x)
		{
    
    
			low = mid + 1;
		}
		else
		{
    
    
			top = mid - 1;
		}
	}	
	if (s == -1)
	{
    
    
		i = top;
		j = low;
	}
	else
	{
    
    
		i = s;
		j = i;
	}
	printf("%d %d",i,j);
	return 0;
}
int main()
{
    
    
	int arr[100];
	int x,n;
	scanf("%d %d",&n,&x);
	for(int i=0;i<n;i++)
	{
    
    
		scanf("%d",&arr[i]);
	}
	search(arr,n,x);
	return 0;
}

動的計画法

動的計画法のアルゴリズムは、いくつかの最適なプロパティを使用して問題を解決するためによく使用されます。このタイプの問題では、多くの実行可能なソリューションが存在する可能性があります。各解は値に対応しており、最適な値を持つ解を見つけたいと考えています。動的計画法のアルゴリズムは分割統治と似ており、解くべき問題をいくつかの部分問題に分解し、まず部分問題を解き、その解から元の問題の解を求めるというのが基本的な考え方です。これらのサブ問題の。分割統治法とは異なり、動的計画法によって解決される問題に適しており、分解によって得られる部分問題は互いに独立していないことがよくあります。

問題の説明

与えられたn(n<=100)アイテムとバックパック。アイテム i の重量はwi、値はvi、バックパックの容量は ですC(C<=1000)質問: バックパック内のアイテムの合計値が最大になるように、バックパック内のアイテムをどのように選択すればよいですか? バックパックに入れるアイテムを選択するとき、各アイテム i: ロードするかしないかの 2 つの選択肢しかありません。ロード。アイテム i を複数回ロードすることも、一部のアイテムのみをロードすることもできませんi

アルゴリズム思考と設計

動的計画法は、テーブルを埋めるプロセスです。現在、バックパックがあり1、バックパックの容量は で105番号が付けられたアイテムがあり1,2,3,4,5、すべてに独自の重量と価格があります。バックパックの容量を超えないように、バックパックに搭載されたアイテムの価値を最大化する必要があります。問題を 5 つのサブ問題に分割できます。1,2,3,4,5サブ質問への回答をテーブルに保存できます。2副問題を解決するには、1副問題の答えを使用する必要があるため (2計画の各ステップを1計画の各ステップと比較する必要があります。2計画のステップが1対応する計画よりも優れていることを示します。次に、2マークを付けます。計画のこのステップが実行可能である. それが最適でない場合, それが1十分である場合, または問題の制約を満たさない場合, 解決策を破棄する.1このステップに対応する解決策をこのステップの解決策として引き続き使用する. サブ問題を解決するには3、サブ問題への回答を使用する必要があり、サブ問題を2解決するには再帰的であり、サブ問題への回答を使用する必要があります。サブ問題は元の問題です。副問題に対する答えは、元の問題に対する最終的な解決策です。完全なコードは次のとおりです。実験結果5455

入力ケース:
5 10
2 6
2
3 6
5 5
4 4 6

	输出结果:15
#define EMPTY
#include<stdio.h>
#include <iostream>
using namespace std ; 
 int main()
 {
    
    
	int V ,T;
	scanf("%d %d",&T,&V);
 	int f[V+1],w[100],c[100];
 	
 	for(int m=0;m<T;m++){
    
    
	 scanf("%d",&c[m]);
 	 scanf("%d",&w[m]);
	 }
 const int INF = -66536  ;
 #ifdef EMPTY
    for(int i = 0 ; i <= V ;i++)
      f[i] = 0 ;    
 #else
    f[0] = 0 ;
    for(int i = 1 ; i <= V ;i++)
      f[i] = INF ;   
 #endif
    
    for(int i = 0 ; i < T ; i++)
    {
    
    
      for(int v = V ; v >= c[i] ;v--)
         {
    
                  
           f[v] = max(f[v-c[i]] + w[i] , f[v]);
         }                 
    }
    cout<<f[V];
    return 0;        
 }

貪欲なアルゴリズム

貪欲なアルゴリズムは、特定の最適解の問題に対するより単純で高速な設計手法です。貪欲なアルゴリズムの特徴は、ステップバイステップで進行することであり、考えられる全体的な状況をすべて考慮するのではなく、現在の状況に基づいた最適化の尺度に基づいて最適な選択を行うことが多いため、最適な方法を見つけるためにすべての可能性を使い果たす必要がありません。解決策 多くの時間が無駄になりました。貪欲なアルゴリズムは、トップダウンの反復法を採用して貪欲な選択を連続して行います. 貪欲な選択が行われるたびに, 問題はより小さなサブ問題に単純化されます. 貪欲な選択の各ステップを通じて, 問題は最適な解決。

問題の説明

(1<=n<=50,000)搾乳する牛が n 頭います。各牛が搾乳される時間間隔を指定しますA,B牛は搾乳するために囲いの中にいる必要があります。牧場は一度に 1 頭の牛しか飼えません。搾乳作業全体を完了するために必要なストールの最小数を尋ねます。(同じ囲いにいる 2 頭の乳牛の場合、搾乳時間間隔が終点で一致することはありません)

アルゴリズム思考と設計

開始時刻または終了時刻で各牛の搾乳時間をソートし、これらの時間間隔に適合する最大のサブセットを見つけて、これらの牛をより早く囲いに配置することができます。配置されていない場合は、時間コレクションの最大のサブセットを見つけて、2 番目の囲いに配置する必要があります。これは配置が完了するまで続き、これらのサブセットの数は囲いの最小数です。完全なコードは次のとおりです。
実験結果

入力サンプル:

5

1 10

2 4

3 6

5 8

4 7

出力例:

4

//判断区间是否重叠 
bool isOverlap(int x[999][2], int i, int j,int s[]) {
    
    
	if (x[i][0] > x[j][1] || x[i][1] < x[j][0]) {
    
    
		for (int m = j + 1; m < i; m++) {
    
    
			if (s[m] == s[j] && isOverlap(x, i, m, s))
				return true;
		}
		return false;
	}
	else
		return true;
}
//贪心 
void Greedy(int x[999][2]) {
    
    
	int s[999] = {
    
     0 };
	for (int i=0; i < 7; i++) {
    
    
		for (int j = 0; j < i; j++) {
    
    
			if (!isOverlap(x, i, j,s)) {
    
    
				s[i] = s[j];
				break;
			}
			else {
    
    
				continue;
			}
		}
		if (s[i] == 0) 
			s[i] = maxNum(s) + 1;
	}
	cout << maxNum(s)<< endl; //所需的畜栏个数
	for (int i = 0; i < 7; i++) {
    
    
		cout << s[i] << endl;//每头牛对应的畜栏
	}
}
//畜栏个数 
int maxNum(int x[]) {
    
    
	int max = x[0];
	for (int i = 1; i < 7; i++) {
    
    
		if (max < x[i]) {
    
    
			max = x[i];
		}
	}
	return max;
}

Guess you like

Origin blog.csdn.net/qq_43774332/article/details/127229302