“王晓东”算法设计之贪心经典习题总结&AC代码(C++)

外币兑换问题

【问题描述】
外币兑换是指利用货币汇兑率的差异将一个单位的某种货币转换为大于一个单位的同种货币。例如,假定 1 美元可以买 0.7 英镑,1 英镑可以买 9.5 法郎,且 1 法郎可以买到 0.16 美元。通过货币兑换,一个商人可以从 1 美元开始买入,得到 0.7×9.5×0.16=1.064 美元,从而获得 6.4%的利润。

算法设计:
给定 n 种货币c1,c2,…,cn的有关兑换率,试设计一个有效算法,用以确定是否存在有收益的兑换可能。

【输入形式】
输入数据:输入数据含有多个测试数据项:每个测试数据的第一行中只有1个整数n(1<=n<=30),表示货币总种类数。其后n行给出n种货币的名称。接下来的一行中有1个整数m,表示有m种不同的货币兑换率。其后m行给出m种不同的货币兑换率,每行有3个数据项ci,rij和cj,表示货币ci和cj的兑换率为rij。每个测试数据项以空行分隔(测试数据以0结束。)。
【输出形式】
对每个测试数据项,如果存在套汇的可能性则输出“Case j Yes”, 否则输出“Case j No”。(注意大小写)

【样例输入】
3
USDollar
BritishPound
FrenchFranc
3
USDollar 0.5 BritishPound
BritishPound 10.0 FrenchFranc
FrenchFranc 0.21 USDollar
3
USDollar
BritishPound
FrenchFranc
6
USDollar 0.5 BritishPound
USDollar 4.9 FrenchFranc
BritishPound 10.0 FrenchFranc
BritishPound 1.99 USDollar
FrenchFranc 0.09 BritishPound
FrenchFranc 0.19 USDollar
0
【样例输出】
case 1 Yes
case 2 No

/*
--------------------------------------
--------------------------------------
--------Problem: 8936.外币兑换问题----
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define MAXN 520
using namespace std;
int n;
double Map[MAXN][MAXN];

void InitMap()  ///初始化地图
{
    
    
    for(int i=1; i<=n; i++)
    {
    
    
        Map[i][i] = 1;  ///自身兑换自身的汇率为1
        for(int j=i+1; j <= n; j++)
            Map[i][j] = Map[j][i] = 0;  ///0代表两种货币不能兑换
    }
}

void Flody() ///借助Flody求解最短路径的思路求解问题
{
    
    
    for(int k=1; k<=n; k++)
    {
    
    
        for(int i=1; i<=n; i++)
        {
    
    
            for(int j=1; j<=n; j++)
            {
    
    
                if(Map[i][k]*Map[k][j]>Map[i][j]) ///如果货币i兑换成k再兑换成j,比i直接兑换成j所得j货币更多,更新
                    Map[i][j] = Map[i][k]*Map[k][j];
            }
        }
    }
}

int main()
{
    
    
    int t=0;
    while(~scanf("%d",&n))
    {
    
    
        if(n==0)  break;
        InitMap();
        int num;
        char name[50],str1[50],str2[50];
        double temp;
        map<string,int>m;   ///用map来处理货币对应的下标
        for(int i=1; i<=n; i++)
        {
    
    
            scanf("%s",name);
            m[name] = i;
        }
        scanf("%d",&num);
        for(int i=0; i<num; i++)
        {
    
    
            scanf("%s%lf%s",str1,&temp,str2);
            int t1 = m[str1];
            int t2 = m[str2];
            Map[t1][t2] = temp;  ///代表t1可以兑换成temp个t2.
        }
        Flody();
        int flag = 1;
        for(int i=1; i<=n; i++)
        {
    
    
            if(Map[i][i]>1)  ///如果第i种货币经过来回兑换后,比原来钱多了,则就可以通过这样的方式赚到钱
            {
    
    
                printf("Case %d Yes\n",++t);
                flag = 0;
                break;
            }
        }
        if(flag) ///代表无论如何兑换,都会赔本,则输出No.
            printf("Case %d No\n",++t);
    }
    return 0;
}

磁盘文件最优存储问题

在这里插入图片描述
【输出形式】
将计算出的最小期望检索时间输出。

【样例输入】
5
33 55 22 11 9
【样例输出】
0.547396

/*
--------------------------------------
--------------------------------------
------Problem: 磁盘文件最优存储问题---
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/
#include <bits/stdc++.h>
#define ll long long 
using namespace std;
bool cmp(int a,int b){
    
    return a>b;}

/*将数组a的值排序使其元素的分布从中间往两边依次减少*/
void strageSort(int n,int a[])
{
    
    
    int i,k,mid;
    sort(a,a+n,cmp);
    mid = n/2;
    int b[n+1];
    b[mid] = a[0];
    for(i=1,k=1; i<n; i++,k++) {
    
    //数组a的值分布从中间往两边依次减少
        b[mid-k] = a[i];
        i++;
        if(i!=n)  b[mid+k] = a[i];
    }
    for(int i=0; i<n; i++)  a[i] = b[i];//经变化后的a数组
}

void  minStorage(int n,int a[])
{
    
    
    int sum = 0;
    for(int i=0; i<n; i++) sum += a[i];
    double result = 0;
        for(int i=0; i<n; i++)
          for(int j=i+1; j<n; j++)    //从磁道0-n-1。计算它们的磁道间的检索时间
            result += (a[i]*1.0/sum)*(a[j]*1.0/sum)*(j-i);
    cout<< result<<endl;
}

int main()
{
    
    
    int n,k,mid,i;
    cin>>n;
    int a[n+1];
    for(int i=0; i<n; i++)  cin>>a[i];
    strageSort(n,a);
    minStorage(n,a);
    return 0;
}

会场安排问题

【问题描述】
 假设要在足够多的会场里安排一批活动,并希望使用尽可能少的会场。设计一个有效的算法进行安排,求出最少需要的会场数。

算法设计:
对于给定的 k 个待安排的活动,计算使用最少会场的时间表。

【输入形式】
输入数据:第一行有 1 个正整数 k,表示有 k 个待安排的活动。接下来的 k 行中,每行有 2 个正整数,分别表示 k 个待安排的活动开始时间和结束时间。时间以 0 点开始的分钟计。
【输出形式】
将计算出的最少会场数输出。

【样例输入】
5
1 23
12 28
25 35
27 80
36 50
【样例输出】
3

/*
--------------------------------------
--------------------------------------
------------Problem: 会场安排问题-----
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/
#include <bits/stdc++.h>
using namespace std;
typedef struct {
    
    int s,f;} Act;

bool cmp(const Act & a, const Act & b){
    
    
	return a.s<b.s ;
}

int main()
{
    
    
	bool cmp(const Act & a, const Act & b);
	int n,i,j,max;
	while(scanf("%d",&n)!=EOF)
	{
    
    
		Act a;
		vector<Act>v;
		int count,k;
		for(i=0; i<n; i++)
		{
    
    
			scanf("%d %d",&a.s,&a.f);
			v.push_back(a);
		}
		sort(v.begin(),v.end(),cmp);

		max=0;
		for(i=0; i<v.size(); i++)
		{
    
    
			count=1;
			for(j=i-1; j>=0; j--)
				if(v[i].s<v[j].f)	count++;
			if(count>max)	max=count;
		}
		printf("%d\n",max);
	}
	return 0;
}

非单位时间任务安排问题

在这里插入图片描述
【样例输入】
7
1 4 70
2 2 60
1 4 50
1 3 40
1 1 30
1 4 20
3 6 80

【样例输出】
110

/*
--------------------------------------
--------------------------------------
-----Problem: 非单位时间任务安排问题--
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/
#include <bits/stdc++.h>
#define ll long long 
using namespace std;
int n;//任务个数 

struct task{
    
    
	int t;//任务时间
	int d;//截止时间
	int w;//惩罚时间 
}; 
task a[100];

int bestw;//存储最短的任务惩罚时间
int w;//当前的任务惩罚时间
int t;//当前所做任务总时间 
int x[100]; 

void backtrack(int i)
{
    
    
	if(i>n)//到达叶节点 
	{
    
    bestw=w;return;} 
	/*约束条件:所做任务总时间是否<=当前任务截止时间,成立进入左子树*/
	if(t+a[i].t<=a[i].d) 
	{
    
    	
		t+=a[i].t;//更新总时间 
		backtrack(i+1);
		t-=a[i].t;//回溯结束时时间要还原 
	} 
	/*限界函数:当前总惩罚是否<=bestw,成立进入右子树,否则剪枝*/ 
	if(w+a[i].w<=bestw) 
	{
    
    
		w=w+a[i].w;
		backtrack(i+1);
		w=w-a[i].w;
	}
}

int main()
{
    
    
	cin>>n;//输入任务个数
	w=0;t=0;bestw=1000;//先将bestw设置为一个较大的值 
	for(int i=1; i<=n; ++i)
		cin>>a[i].t>>a[i].d>>a[i].w;
	backtrack(1);
	cout<<bestw<<endl;
	return 0; 
}

硬币找钱问题

/*
--------------------------------------
--------------------------------------
------------Problem: 硬币找钱问题-----
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/
#include <bits/stdc++.h>
using namespace std;

const int N = 20000 ;
int change[N]; // change[i]为面值为i的钱至少需要的硬币个数
int dp[N]; // dp[i]为当前拥有的硬币数量条件下表示面值为i的最少硬币个数
int value[6] = {
    
    1,2,4,10,20,40}; // 每种硬币对应面值,依次为1,2,4,10,20,40个五分,即5,10,20,50,100,200;
int number[6]; // 对应于当前拥有的每种硬币个数

void init() // 计算change[i]
{
    
    
    int i,j;
    for(i=0; i<N; i++)  change[i] = -1;
    change[0] = 0;
    for(i=0; i<6; i++)
    {
    
    
        for(j=value[i]; j<N; j++) // 这里使用完全背包,不能理解的话可参考背包九讲
        {
    
    
            if(change[j-value[i]]!=-1)
            {
    
    
                int temp = change[j-value[i]]+1;
                if(change[j]==-1 || temp<change[j])  change[j] = temp;
            }
        }
   }
}

int main()
{
    
    
    init(); //计算出change[i]

    while (scanf(" %d%d%d%d%d%d " , &number[0], &number[1], &number[2], &number[3], &number[4], &number[5]) != EOF)
    {
    
    
        int i,j,kk,sum=0;
        for(kk=0; kk<6; kk++)  sum += number[kk];
        if(sum==0 )  break;
        double weight;
        scanf("%lf" ,&weight);
        weight = weight*100 ;
        int w = int(weight+0.0000001); //处理精度问题

        if(w%5!=0) // 若不能整除,则无法表示
        {
    
    
            printf("impossible\n");
            continue ;
        }
        else  w = w/5;
        memset(dp,-1,sizeof(dp));
        dp[0] = 0;
        int bigger = 0;
        for(i=0; i<6; i++) //计算顾客支付面值i需要的最少硬币数dp[i]
        {
    
    
            while(number[i]--) //将混合背包拆成01背包做,写水了点。。。
            {
    
    
                bigger = bigger+value[i];
                for(j=bigger; j>=value[i]; j--)
                {
    
    
                    if(dp[j-value[i]]!=-1)
                    {
    
    
                        int temp = dp[j-value[i]]+1;
                        if(dp[j]==-1 || temp<dp[j])  dp[j] = temp;
                    }
                }
            }
        }
        int ans = -1;
        for(i=w; i<=bigger; i++) //寻找最少硬币组合
        {
    
    
            if(dp[i]!=-1)
            {
    
    
                int need = i-w;
                if(change[need]!=-1)
                {
    
    
                    int temp = dp[i]+change[need];
                    if(ans==-1 || ans>temp)  ans = temp;
                }
            }
        }

        if(ans!=-1)  printf("%d\n",ans);
        else  printf("impossible\n");
    }
    return 0;
}

汽车加油问题

/*
--------------------------------------
--------------------------------------
-----------Problem: 汽车加油问题------
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/
#include <bits/stdc++.h>
using namespace std;

void greedy(int d[],int n,int k) {
    
    //汽车加满油之后可以行驶n千米,沿途有k个加油站
    int num = 0;
    for(int i = 0;i <= k;i++) {
    
    
        if(d[i] > n) {
    
    //加油站之间的距离
            cout<<"no solution\n"<<endl;
            break;
        }
    }
    for(int i = 0,sum = 0;i <= k;i++) {
    
    
        sum += d[i];//加油站间距离相加
        if(sum > n) {
    
    //车无法达到第i个加油站,加油一次,s等于从加过油的地方开始计
            num++;
            sum = d[i];
        }
    }
    cout<<num<<endl;
}
 
int main() 
{
    
    
    int i,n,k;
    int d[1000];
    cin>>n>>k;
    for(i=0; i<=k; i++)    cin>>d[i];
    greedy(d,n,k);
}

猜你喜欢

转载自blog.csdn.net/Luoxiaobaia/article/details/109481796