算法俱乐部前两次活动题目分析by邵明

本文解析了四道经典的编程题目,包括货币兑换、日历游戏、钓鱼问题和陪审团妥协,涵盖了模拟、贪心算法、动态规划等多种解题思路。

第一次讨论

首先声明一下:我写的程序比较难看懂,有时候写得长了如果回过去看,我自己也看不懂,而且在说明题意和方法上有些地方可能说的不是很清楚,自己的表达能力比较差,也请多多见谅。

第一题1058 Currency Exchange

这个题目就是一开始就给出五个国家的之间的汇率,然后题目中给一个旅游路线和开始旅游前的钱数,然后问题是计算出经旅游后手中还有多少钱。

这个问题我就模拟了一下,比较苯的办法,没什么算法可言。

具体代码如下:

#include "stdafx.h"

#include "stdio.h"

 

int main(int argc, char* argv[])

{

       int num,n,trip[10],last_city,curr_city,temp_m,i,j;

       double rate[5][5],m;

       scanf("%d",&num);

       while(num>0)

       {

              for(i=0;i<5;i++)

                     for(j=0;j<5;j++)

                            scanf("%lf",&rate[i][j]);

              while(1)

              {

                     scanf("%d",&n);

                     if(n==0)

                            break;

                     for(i=0;i<n;i++)

                            scanf("%d",&trip[i]);

                     scanf("%lf",&m);

                     last_city=0;

                     for(i=0;i<n;i++)

                     {

                            curr_city=trip[i]-1;

                            m=rate[last_city][curr_city]*m;

                            m=m*100;

                            temp_m=int(m);

                            if((m-temp_m)>=0.5)

                                   m=temp_m+1;

                            else

                                   m=temp_m;

                            m=m/100;

                            last_city=curr_city;

                     }

                     curr_city=0;

                     m=rate[last_city][curr_city]*m;

                     m=m*100;

                     temp_m=int(m);

                     if(m-temp_m>=0.5)

                            m=temp_m+1;

                     else

                            m=temp_m;

                     m=m/100;

                     printf("%.2f/n",m);

              }

              if(num!=1)

                     printf("/n");

              num--;

       }

       return 0;

}

 

第二题1024 Calendar Game

       题目我没做,是一个博弈题目,大概题意是由两个人在玩日历游戏,每个人轮流走,可以选者走下一天,也可以走到下一个月的这一天,比如当前你在200212,你可以走到199913或者199922,但是如果下一个月没有这天的话你只能走下一天,比如1999130,但是下个月没有30号,所以你唯一的选择是走到1999131。谁先走到 2001114后面谁就输了。有两个人比赛AdamEveAdam先走,看Adam有没有策略可以赢。有的话输出YES,否则输出NO以下思路是学姐提供的,用一个一维的数组存储每一天Adam有没有赢得策略,有的话存1,没的话存0,刚开始从2001113开始存1,后面的话是根据前一天或前一个月的状态来决定这天的状态,依次类推。比如200032可以根据200033200042决定,只要有一个为0200032这一天才可以设为1。具体程序没实现过,想想应该可以的。

 

第三题1161 Gone Fishing

     题目是叫我们求出在规定的时间内最多可以钓到的鱼的条数。题目给了我们可用的时间h,湖的个数n,每个湖初始鱼的条f,每在一个湖里钓五分钟之后鱼的数目的减少量d,从前一个湖到后一个湖需要花费的时间t,湖与胡之间的路是单项的,就是一旦走到后面一个湖上去了就不能回来。这道题可以用贪性算法做。钓鱼的湖从第一个湖,前两个湖,前三个一直往后推,然后比较哪个方案钓的鱼比较多。每次都是先把湖与湖之间的耗费时间先剪掉,然后挑那个鱼最多的湖钓,更新湖里鱼的条数,再在有最多鱼的湖里钓,依次类推,直到时间花完。

具体代码如下:

#include "stdafx.h"

#include "iostream.h"

 

int main(int argc, char* argv[])

{

       int n,h,k,fi[25],di[25],ti[25],first,i,j,temp_fi[25],max_fi,max,temp_max,need_h,temp_h,temp_time[25],time[25];

       first=0;

       while((cin>>n)&&(n!=0))

       {

              if(first==0)

                     first=1;

              else

                     cout<<endl;

              cin>>h;

              for(i=0;i<n;i++)

                     cin>>fi[i];

              for(i=0;i<n;i++)

                     cin>>di[i];

              for(i=1;i<n;i++)

                     cin>>ti[i];

              ti[0]=0;

              h=h*12;

              max=-1;

              temp_max=0;

              max_fi=-1;

              need_h=0;

              for(i=0;i<n;i++)

                     temp_time[i]=0;

              for(i=0;i<n;i++)

              {

                     temp_h=h;

                     temp_max=0;

                     for(j=0;j<=i;j++)

                     {

                            temp_fi[j]=fi[j];

                            temp_time[j]=0;

                     }

                     need_h=need_h+ti[i];

                     temp_h=h-need_h;

                     if(temp_h<=0)

                            break;

                     while(temp_h>0)

                     {

                            max_fi=-1;

                            for(j=0;j<=i;j++)

                            {

                                   if(max_fi<temp_fi[j])

                                   {

                                          max_fi=temp_fi[j];

                                          k=j;

                                   }

                            }

                            if(temp_fi[k]<=di[k])

                                   temp_fi[k]=0;

                            else

                                   temp_fi[k]=temp_fi[k]-di[k];

                            temp_max=temp_max+max_fi;

                            temp_time[k]++;

                            temp_h--;

                     }

                     if(temp_max>max)

                     {

                            max=temp_max;

                            for(j=0;j<n;j++)

                                   time[j]=temp_time[j];

                     }

              }

              for(j=0;j<n;j++)

              {

                     cout<<time[j]*5;

                     if(j!=n-1)

                            cout<<", ";

              }

              cout<<endl;

              cout<<"Number of fish expected: "<<max<<endl;

       }

      

       return 0;

}

 

第四题 1303 Jury Compromise

       题目讲的是有一个国家在审案子的时候都要组建一个陪审团,陪审团的成员是从候选的人群中选出来的。这些候选的人每个人都有两个值,分别代表被告和原告给他们的值,从0-200代表对此人很厌恶,20表示对此人非常满意。我们的任务是要从这些人中选出一些人满足最佳要求。D(J)=d(i) 1=<i<=m, P(J)=p(i) 1=<i<=m,m是陪审团的人数。最佳要求就是|D(J)-P(J)|最小,当有两组选择,他们的|D(J)-P(J)|一样,那么选那组使|D(J)+P(J)|最大的。

本题用动态规划做。我也是看了别人的思路才知道怎么做的,但是还没提交成功,路径的存储还没解决。大概思路是这样的:

枚举出所有的得分差,然后求最高得分和。由于m是从0~20D(J)-P(J)的差值是从-20~20的,所以得分差从-400~400,有801种可能,可以开一个三维数组cost[201][21][801]cost[i][j][k] 表示从前i个人中选j个人时得分差为k的最高得分和。

递推公式是cost[i][j][k]=max(cost[i-1][j][k],cost[i-1][j-1][k-diff[i]]+sum[i]) diff[i]sum[i]是第i个人的差值和和值。等表全部填完后,检察cost[n][m][k],如果cost[n][m][k]存在,选k值最小的就是答案了。

 

 

第二次讨论

第一题1076 Gene Assembly

题目的意思是给你一组核苷酸,每一个都有开始和结束,我们的问题是从这些核苷酸中找出能组成的最长的链,要求在链中前一个核苷酸的结束要比后一个核苷酸的开始要早。这题是用贪心算法。先根据结束时间排序,结束时间早的排在前面。然后选择第一个核苷酸,再在剩下的里面找到与这个核苷酸兼容的第一个核苷酸,找完后,再在剩下的里面找与第二个兼容的第一个核苷酸,依次类推,直到没有核苷酸可找,就停止。

具体代码如下:

#include "stdafx.h"

#include "iostream.h"

 

int main(int argc, char* argv[])

{

       int n,start[1001],i,j,end[1001],num[1001],temp_start,temp_end,temp_num,number,path[1001],last_num;

       while((cin>>n)&&(n!=0))

       {

              for(i=1;i<=n;i++)

              {

                     cin>>start[i]>>end[i];

                     num[i]=i;

              }

              for(i=2;i<=n;i++)

              {

                     temp_start=start[i];

                     temp_end=end[i];

                     temp_num=num[i];

                     for(j=i-1;j>=1;j--)

                     {

                            if(temp_end<end[j])

                            {

                                   start[j+1]=start[j];

                                   end[j+1]=end[j];

                                   num[j+1]=num[j];

                            }

                            else

                                   break;

                     }

                     start[j+1]=temp_start;

                     end[j+1]=temp_end;

                     num[j+1]=temp_num;

              }

              number=1;

              path[1]=num[1];

              last_num=1;

              j=2;

              i=2;

              while(i<=n)

              {

                     if(start[i]>end[last_num])

                     {

                            path[j++]=num[i];

                            last_num=i;

                            i++;

                            number++;

                     }

                     else

                            i++;

              }

              //cout<<number<<' ';

              for(i=1;i<number;i++)

                     cout<<path[i]<<' ';

              cout<<path[i]<<endl;

       }

       return 0;

}

 

第二题1203 Swordfish

题目是给我们一组城市的二维坐标,计算一条路径能把所有的城市连起来的但总的距离最小的通路。就是最小生成树问题。

具体代码如下:

#include "stdafx.h"

#include "stdio.h"

#include "math.h"

 

int main(int argc, char* argv[])

{

int n,i,j,k,temp,know[101],number,flag;

double postion[101][2],dis[101][101],distance,min,cost;

number=1;

flag=1;

while((scanf("%d",&n))&&(n!=0))

{

       if(flag==1)

              flag=2;

       else

              printf("/n");

       for(i=1;i<=n;i++)

              scanf("%lf %lf",&postion[i][0],&postion[i][1]);

       for(i=1;i<=n;i++)

              for(j=1;j<=n;j++)

              {

                     if(i==j)

                            dis[i][j]=1000000000;

                     else

                     {

                     distance=(postion[i][0]-postion[j][0])*(postion[i][0]-postion[j][0])+(postion[i][1]-postion[j][1])*(postion[i][1]-postion[j][1]);

                            dis[i][j]=sqrt(distance);

                     }

              }

       for(i=1;i<=n;i++)

              know[i]=0;

       know[1]=1;

       cost=0;

       for(i=2;i<=n;i++)

       {

              min=100000000;

              for(j=1;j<=n;j++)

              {

                     if(know[j]==1)

                     {

                            for(k=1;k<=n;k++)

                                   if((dis[j][k]<min)&&(know[k]==0))

                                   {

                                          min=dis[j][k];

                                          temp=k;

                                   }

                     }

              }

              if(min!=100000000)

              {

                     cost=cost+min;

                     know[temp]=1;

              }

       }

       printf("Case #%d:/n",number);

       printf("The minimal distance is: %.2f/n",cost);

       number++;

}

return 0;

}

 

第三题1082 Stockbroker Grapevine

这道题目是最短路径,求城市到别的城市的最短路径。可以用最短路径算法解决。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值