筆試題總結:貪心算法(或動態規划)


概念:

當一個問題具有最優子結構性質時,可用動態規划算法,有時會有更簡單有效的算法,那就是貪心算法,貪心算法是通過一系列的選擇來得到問題的解,貪心算法並不從整體最優上加以考慮,所做的選擇只是在某種意義上的局部最優解。但對范圍相當廣的許多問題能產生整體最優解。在一些情況下,即使貪心算法不能得到整體最優解,但其最終結果卻是最優解的很好的近似解。

貪心算法的基本要素:

貪心選擇性質:所求解的問題的整體最優解可以通過一系列局部最優的選擇來,即貪心選擇達到。貪心選擇所依賴的是以前所做過的選擇,而對以后所做的選擇沒有關系。

最優子結構性質:一個問題的最優解包含其子問題的最優解。

貪心算法與動態規划的區別:

動態規划是通過自底向上的方式解決子問題,貪心算法是通過自頂向下的迭代方式做出貪心選擇,求解問題的最優解。兩共同點是都具有最優子結構性質。

動態規划:(0-1)背包問題

https://blog.csdn.net/qq_38410730/article/details/81667885

類似:

1.歡聚時代:容量M,電影N部,每部喜愛值不一樣,電影大小不一樣,求不超過容量最喜歡的值

100 5//容量,5部電影

29 28 19 18 20//電影容量

9   4     3   8 10//每部喜愛值

以上是典型 的0-1背包問題,動態規划來解決

思路:

  weight[N]={29 28 19 18 20} 

  value[N]={9   4     3   8 10}

容量N=100

(i) weight(j) value
0 0 0
1 29 9
2 28 4
3 19
4 18
5 20 10

 

B(i,j)//意思是,可選第i件商品以前的任意商品,還剩余容量j的最大價值

B(i,j)---->j(剩余容量)<weight[i](第i件物品的容量,重量),只能選第i-1件以前的,即b(i-1,j)

   ---------->選i, B(i-1,j-values[i])

   ---------》不選i,  B(i-1,j)

動態規划:創建一個二維數組

 

 

//背包問題
  int dp(vector<int>& value, vector<int>& weight, int cap,int n)
{
    vector<vector<int>> vvi(n + 1, vector<int>(cap + 1, 0));
    for (int i = 1; i < n + 1;i++)
    {
        for (int j = 1; j < cap + 1;j++)
        {
            if (j < weight[i]) vvi[i][j] = vvi[i - 1][j];
            else
            {
                int A = vvi[i - 1][j - weight[i]]+value[i];
                int B = vvi[i - 1][j];
                vvi[i][j] = max(A,B);
            }
        }
    }
    return vvi[n][cap];
}
int main()
{
    int n, cap;
    int v, w;
    cin >> n >> cap;
    vector<int>value(n+1,0), weght(n+1,0);
    
    for (int i = 1; i < n+1;i++)
    {
        cin >> v;
        value[i]=v;
    }
    for (int i = 1; i < n+1; i++)
    {
        cin >> w;
        weght[i]=w;
    }
    for (auto i:value)
    {
        cout << i << " ";
    }
    cout << endl;
    for (auto i : weght)
    {
        cout << i << " ";
    }
    cout << endl;
    cout << n << cap << endl;
    cout <<dp(value,weght,cap,n)<<endl;
    system("pause");
}

 

下面的解法是錯誤的

#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
int main()
{
    int cap,num,tmp;
    map<int, int, greater<int>> love_size;
    cin >> cap>>num;
    cout << cap << ":" << num << endl;
    vector<int> movie, love;
    for (int i = 0; i < num;i++)
    {
        cin >> tmp;
        movie.push_back(tmp);
    }
    for (int i = 0; i < num; i++)
    {
        cin >> tmp;
        love.push_back(tmp);
    }
    for (int i = 0; i < num;i++)
    {
        love_size.insert(make_pair(love[i],movie[i]));
    }
    int love_sum=0;
    int movie_cap = 0;
    for (auto v:love_size)
    {

        movie_cap += v.second;
        love_sum += v.first;
        cout << "select:" << v.first << ":" << v.second  <<":"<<love_sum<<endl;
        if (movie_cap >= cap)
        {
            if (movie_cap> cap) love_sum -= v.first;
            break;
        }

    }
    cout << love_sum << endl;
    system("pause");
}
    

華為:一百塊錢需要買100只雞,公雞5元一只,母雞3元一只,小雞一元三只。請輸出所有可能的情況。

5*x+3*y+z/3=100

x+y+z=100

0=<x<=25

0=<y<=33

0=<z/3<=100

#include<iostream.h>
void main()
{
    int x,y,z,count=0;
    cout<<"百錢買百雞的方案有:"<<endl;
    for(x=0;x<=20;x++)
        for(y=0;y<=33;y++)
            for(z=0;z<=300;z=z+3)
             if(5*x+3*y+z/3==100&&x+y+z==100)
             {
                 ++count;
                 cout<<count<<":"<<x<<","<<y<<","<<z<<endl;
             }
            
}

 

類似的比如百度:

 

 1,2

N

可以考慮使用動態規划或者斐波拉數列

F(N)=F(N-1)+F(N-1) //F表示多少中方法

n=1 return 1

n=2  return 2

return f(n-1)+f(n-2)

或者

void step(int n)
{
    vector<long long> v(n+1, 0);
    if(n>=1) v[1] = 1; 
    if(n>=2) v[2] = 2;
    for (int i = 3; i <= n;i++)
    {
        v[i] = v[i - 1] + v[i - 2];
    }
    cout << v[n] << endl;
}
int main()
{
    step(1);
    step(2);

    step(3);
    step(4);
    step(5);
    step(10);
    system("pause");
}

 

 //間隔,不能選相鄰的數字,使其最優(和最大)

 

//1 2 4 1 7 8 3
//4 1 1 9 3
//opt[i] = max(opt[i - 2] + vi[i] , opt[i-1]);

int dp_dg(vector<int>& vi,int n)//最后一個元素
{
	int A, B;
	if (n == 0) return vi[0];
	else if (n == 1) return max(vi[0], vi[1]);
	else
	{
		
		A = dp_dg(vi, n - 2) + vi[n];
		B = dp_dg(vi, n - 1);
		return max(A, B);
		
	}
}
int dp(vector<int>& vi)//最后一個元素
{
	int A, B;
	vector<int> v_dp(vi.size(),0);
	v_dp.resize(vi.size());
	v_dp[0] = vi[0];
	v_dp[1] = max(vi[1], vi[0]);
	for (int i = 2; i < vi.size();i++)
	{
		A = vi[i] + v_dp[i - 2];
		B = v_dp[ i - 1];
		v_dp[i] = max(A,B);
	}
	return v_dp[v_dp.size() - 1];
}
int main()
{
	int num,tmp;
	cin >> num;
	vector<int> vi(num);
	for (int i = 0; i < num;i++)
	{
		cin >> tmp;
		vi.push_back(tmp);
	}

	cout<<dp(vi)<<endl;
	system("pause");
}

  

//3 34 4 12 5 2能否湊出9,能,返回true,否則返回false
//3 34 4 12 5 2
//s=9 true
//subset(i,s)=subset(i-1,s-v[i])
//subset(i,s)=subset(i-1,s);
條件:
//1.i=0,return v[i]==s
//2,s=0 return true
//v[i]>s--->subset(i-1,s);
/*bool subset1(vector<int>& vi, int i,int s)
{
    int A, B;
    if (i == 0) return vi[0] == s;
    if (s == 0) return true;
    if (vi[i] > s) return subset(vi, i - 1, s);
    A = subset(vi, i - 1, s - vi[i]);
    B = subset(vi, i - 1, s);
    return A || B;

}*/
 bool subset(vector<int>& vi, int s)
{
    vector<vector<bool>> vvi(vi.size(),vector<bool>(s+1));
    int A, B;
    
    for (int i = 0; i < s + 1;i++)
        vvi[0][i] =false;
    vvi[0][vi[0]] = true;
    for (int i = 0; i < vi.size();i++)
    {
        vvi[i][0] = true;
    }
    for (int i = 1; i < vi.size();i++)
    {
        for (int j = 1; j < s + 1; j++)
        {
            if (vi[i]>j) vvi[i][j] = vvi[i - 1][j];
            else
            {
                A = vvi[i - 1][j - vi[i]];
                B = vvi[i - 1][j];
                vvi[i][j] = A || B;
            }
        }
        
    }
    return vvi[vi.size() - 1][s];
}
int main()
{
    int n,tmp;
    vector<int> vi;
    cin >> n;
    for (int i = 0; i < n;i++)
    {
        cin >> tmp;
        vi.push_back(tmp);
    }
    cout<<boolalpha<<subset(vi,9)<<endl;
    cout << boolalpha << subset(vi, 10) << endl;
    cout << boolalpha << subset(vi, 12) << endl;
    cout << boolalpha << subset(vi, 9) << endl;
    cout << boolalpha << subset(vi, 13) << endl;
    system("pause");
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM