貪心問題是算法中解決問題的一種策略,每次都選擇當前最優的方法,雖然結果不一定正確,但是在解決一些問題中是非常有效並且是正確的。
第一題硬幣問題
問題描述:有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;
}
優先隊列用的太好了,參考的別的文章鏈接