C/C++之貪心問題

貪心問題是算法中解決問題的一種策略,每次都選擇當前最優的方法,雖然結果不一定正確,但是在解決一些問題中是非常有效並且是正確的。

第一題硬幣問題

問題描述:有1元,5元,10元,50元,100元,500元的硬幣各c1,c5,c10,c50,c100,c500枚.
現在要用這些硬幣來支付A元,最少需要多少枚硬幣?

/**
*硬幣問題
有1元,5元,10元,50元,100元,500元的硬幣各c1,c5,c10,c50,c100,c500枚.

現在要用這些硬幣來支付A元,最少需要多少枚硬幣?

假定本題至少存在一種支付方案.

0≤ci≤10^9

0≤A≤10^9

輸入:

第一行有六個數字,分別代表從小到大6種面值的硬幣的個數

第二行爲A,代表需支付的A元

樣例:

輸入

3 2 1 3 0 2
620輸出

6說明:1500+250+110+25,共6枚
*/
#include<iostream>
using namespace std;
int coin[]={1,5,10,50,100,500};
int number[6];
int coin_length=5;//記錄數組下標 
int main()
{
	//count保存每種金額的數量,total_count保存總數 
	int total,total_count=0,count;
	for(int i=0;i<=coin_length;i++)
	{
		scanf("%d",&number[i]);
	}
	scanf("%d",&total);
	while(total)
	{
		count=min(total/coin[coin_length],number[coin_length]);
		total-=(count*coin[coin_length]);
		total_count+=count;
		coin_length--;
	}
	printf("%d",total_count);
	return 0; 
} 

第二題快速渡河

問題描述:一隊人(N個人)期望跨河,有一條船,一次只能載2個人,過河之後需要有一個人劃回來,所有人才能夠跨河,每個人划船速度都不同,兩個人一組整體速度是由划船速度較慢的決定的。問題:確定一種策略用最少的時間所有人都能過河。

/**
一隊人(N個人)期望跨河,有一條船,一次只能載2個人,過河之後需要有一個人劃回來,所有人才能夠跨河,每個人划船速度都不同,兩個人一組整體速度是由划船速度較慢的決定的。問題:確定一種策略用最少的時間所有人都能過河。

輸入:
方案數:T(1<=T<=20)
人數:N<1000
速度:<100s
輸出:
最少的時間
樣例:
輸入:
1
4
1 2 5 10
輸出
17
*/

#include<iostream>
#include<algorithm>
using namespace std;
int speed[1200]; 
int main()
{
	
	int T;
	scanf("%d",&T);
	for(int i=0;i<T;i++)
	{
		int left,ans=0;
		scanf("%d",&left);
		for(int i=0;i<left;i++)
		{
			scanf("%d",&speed[i]);
		}
		sort(speed,speed+left);
		while(left>0)
		{
			if(left==1)//剩餘一人
			{
				ans+=speed[0];
				break;
			 } 
			 else if(left==2)//剩餘兩人
			 {
			 	ans+=speed[1];
			 	break;
			  } 
			  else if(left==3)//剩餘三人
			  {
			  	ans+=speed[2]+speed[0]+speed[1];
			  	break;
			   } 
			   else
			   {
			   	//第一種策略,先讓0,1到達對岸,1返回,在讓left-2,left-1到達對岸,0返回 
			   	int s1=speed[1]+speed[0]+speed[left-1]+speed[1];//speed[1]爲0,1到達對岸的時間,speed[1]爲1單獨返回的時間,speed[left-1]爲left-2,left-1到達對岸的時間,speed[0]爲0單獨返回的時間 
			   	//第二種策略,先讓0,left-1到岸對岸,0返回,再讓0,left-2到達對岸,1返回 
				   int s2=speed[left-1]+speed[left-2]+2*speed[0];//speed[left-1]爲0,left-1到達對岸的時間,speed[0]爲0單獨返回的時間,speed[left-2]爲0,left-2到達的時間,speed[0]爲0單獨返回的時間 
			   	ans+=min(s1,s2);
			   	left-=2;
			   }
			}
		printf("%d",ans);
	}
	return 0; 
} 

第三題區間調度

問題描述:有n項工作,每項工作分別在si開始,ti結束。對每項工作,你都可以選擇參加或不參加,但選擇了參加某項工作就必須至始至終參加全程參與,即參與工作的時間段不能有重疊(即使開始的時間和結束的時間重疊都不行)。

/*
問題描述:

有n項工作,每項工作分別在si開始,ti結束。對每項工作,你都可以選擇參加或不參加,但選擇了參加某項工作就必須至始至終參加全程參與,即參與工作的時間段不能有重疊(即使開始的時間和結束的時間重疊都不行)。

限制條件:

1<=n<=100000

1<=si<=ti,=109

樣例:

輸入

n=5

s={1,2,4,6,8}

T={3,5,7,9,10}

輸出

3(選擇工作1, 3, 5)

解決策略:
排序是第一標準爲結束時間,第二標準爲起始時間,相同結束時間的工作是不能同時參加的,
但是在數組中,起始時間晚的時間在數組的低地址除,而起始時間晚的工作在高地址除,能
保證相同結束時間選擇出工作時間最短的工作,最大限度的 參加更多的工作。 
*/
#include<iostream>
#include<algorithm>
using namespace std;
class Time{
	public:
		int start;
		int end;
};
Time time[100000]; 
int cmp(Time time1,Time time2)
{
	if(time1.end!=time2.end)
		return time1.end<time2.end;
	else
		return time1.start>time2.start;
}
int main()
{
	int n,count=1;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		scanf("%d",&time[i].start);
	for(int j=0;j<n;j++)
		scanf("%d",&time[j].end);
	sort(time,time+n,cmp);
	int t=time[0].end;
	for(int i=1;i<n;i++)
	{
		if(time[i].start>t)
		{
			t=time[i].end;
			count++;
		}
	}
	cout<<count;
	return 0; 
} 

第四題區間選點問題

問題描述:數軸上有n個閉區間[ai,bi]。取儘量少的點,使得每個區間內都至少有一個點(不同區間內含的點可以是同一個)。

/*
問題描述:

數軸上有n個閉區間[ai,bi]。取儘量少的點,使得每個區間內都至少有一個點(不同區間內含的點可以是同一個)。

解決策略:
排序是標準爲終點 
*/
#include<iostream>
#include<algorithm>
using namespace std;
class Time{
	public:
		int start;
		int end;
};
Time time[100000]; 
int cmp(Time time1,Time time2)
{
	return time1.end<time2.end;
}
int main()
{
	int n,count=1;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		scanf("%d",&time[i].start);
	for(int j=0;j<n;j++)
		scanf("%d",&time[j].end);
	sort(time,time+n,cmp);
	int t=time[0].end;
	for(int i=1;i<n;i++)
	{
		if(time[i].start>t)
		{
			t=time[i].end;
			count++;
		}
	}
	cout<<count;
	return 0; 
} 

石子游戲

問題描述
  石子游戲的規則如下:
  地上有n堆石子,每次操作可選取兩堆石子(石子個數分別爲x和y)並將它們合併,操作的得分記爲(x+1)×(y+1),對地上的石子堆進行操作直到只剩下一堆石子時停止遊戲。
  請問在整個遊戲過程中操作的總得分的最大值是多少?
輸入格式
  輸入數據的第一行爲整數n,表示地上的石子堆數;第二行至第n+1行是每堆石子的個數。
輸出格式
  程序輸出一行,爲遊戲總得分的最大值。
樣例輸入
10
5105
19400
27309
19892
27814
25129
19272
12517
25419
4053
樣例輸出
15212676150
數據規模和約定
  1≤n≤1000,1≤一堆中石子數≤50000

#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <math.h>
#include <queue>
using namespace std;
int main()
{
	priority_queue<long long,vector<long long>,less<long long> > stones;
	long long t,x,y,ans=0;
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>t;
		stones.push(t);
	}
	while(stones.size()>=2)
	{
		x=stones.top();
		stones.pop();
		y=stones.top();
		stones.pop();
		ans+=(x+1)*(y+1);
		stones.push(x+y);
	}
	cout<<ans;
	return 0;
}

解法不難,剛開始以爲需要字符數組解決,但沒想到long long如此大

線段和點

給你n個點,m個區間,求出最少的點集使得覆蓋所有的區間

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxx=1e4+100;
struct node{
	int s,e;
	bool operator<(const node &a)const{
		if(s!=a.s) return s<a.s;
		else return e>a.e;
	}
}p[maxx];
int a[maxx];
int n,m;

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=m;i++) scanf("%d%d",&p[i].s,&p[i].e);
	sort(p+1,p+1+m);
	int k,i,j,st=1;
	for(k=0;k<n;k++)//操作的次數=最少需要的點數
	{
		int _max=1;
		for(i=1;i<=n;i++)
		{
			for(j=st;j<=m;j++) if(p[j].s>a[i]||p[j].e<a[i]) break;
			if(j>_max) _max=j;//看這個點最多可以滿足多少個區間。
		}
		st=_max;//下次開始的時間就在上一次點的地方開始,尋找滿足的點
		if(st==m+1) break;//所有的線段滿足了,就直接退出。
	}
	if(k==n) cout<<"-1"<<endl;
	else cout<<k+1<<endl;
	return 0;
}

排隊打水問題

題目描述
有n個人排隊到m個水龍頭去打水,他們裝滿水桶的時間t1, t2 , ……, tn爲整數且各不相同,應如何安排他們的打水順序才能使他們花費的總時間最少? 只有一組輸入數據哦。

輸入
4 2

2 6 4 5

輸出
23

#include <algorithm>
#include <iostream>
#include <vector>
#include <math.h>
#include <queue>
int arr[1000];
using namespace std;
int main()
{
	int ans=0;
	priority_queue<int,vector<int>,greater<int> > s;
	int m,n,t;
	cin>>m>>n;
	for(int i=0;i<m;i++)
		cin>>arr[i];
		sort(arr,arr+m);
	for(int i=0;i<n;i++)
	{
		s.push(arr[i]);
		ans+=arr[i];
	}
	for(int i=n;i<m;i++)
	{
		int now=s.top();
		s.pop();
		now+=arr[i];
		ans+=now;
		s.push(now);
	}
	cout<<ans;
	return 0;
}

優先隊列用的太好了,參考的別的文章鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章