2006百度之星设计大赛-------(饭团的烦恼)

“午餐饭团”是百度内部参与人数最多的民间组织。

同一个部门的、同一所大学的、同一年出生的、使用同一种型号电脑的员工们总是以各种理由组织各种长期的、临时的饭团。

参加饭团,不仅可以以优惠的价格尝到更加丰富的菜式,还可以在吃饭的时候和同事们增进感情。
但是,随着百度的员工越来越多,各个饭团的管理变得繁杂起来。特别是为了照顾员工们越来越挑剔的胃,饭团的点菜负责人的压力也越来越大。现在,这个任务就交给“百度之星”了,因为,你将要为所有的百度饭团设计一个自动点菜的算法。

饭团点菜的需求如下:
1.经济是我们要考虑的一个因素,既要充分利用百度员工的午餐补助,又不能铺张浪费。因此,我们希望最后的人均费用越接近12元越好。
2.菜式丰富是我们要考虑的另一个因素。为简单起见,我们将各种菜肴的属性归结为荤菜,素菜,辛辣,清淡,并且每个菜只能点一次。
3.请谨记,百度饭团在各大餐馆享受8折优惠。

输入要求:
1.输入数据第一行包含三个整数N,M,K(0<N<=16,0<M<=N,0<K<=12),分别表示菜单上菜的数目,饭团需要点的菜的数目,就餐的人数;
2.紧接着N行,每行的格式如下:
菜名(长度不超过20个字符) 价格(原价,整数)是否荤菜(1表示是,0表示否) 是否辛辣(1表示是,0表示否);
3.第N+2行是 a b c d 四个整数,分别表示需要点的荤菜,素菜,辛辣,清淡菜的数目。例:
3 2 2
水煮鱼 30 1 1
口水鸡 18 1 1
清炖豆腐 12 0 0
1 1 1 1
样例:in.txt

输出要求:
对于每组测试数据,输出数据包含M+1行,前M行每行包含一个菜名(按菜名在原菜单的顺序排序)。第M+1行是人均消费,结果保留两位小数。例:
口水鸡
清炖豆腐
12.00
样例

// ***************************************************************

// Main   version: 1.0   · date: 10/02/2007

// -------------------------------------------------------------
// Write By 凌剑(Bujiwu)
// -------------------------------------------------------------
// Copyright (C) 2007 - All Rights Reserved

// ***************************************************************

//

// ***************************************************************

#include <iostream>
#include <string>
#include <fstream>
#include <math.h>
using namespace std;
 
double AverageMinus=0; // 人均消费与的偏移量
double AverageCost=0; // 人均消费
bool    Flag=true;     // 满足条件日第一次偏移量标志
 
// 菜单信息结构体
typedef struct 
{
    string DishName// 菜名

    int Price;        //价格

    int MeatDish;     //是否为晕菜

    int NaDish;      //是否为辛辣

}Dish;
 
// 点菜信息结构体
typedef struct 
{

    int MenuTotal;       //菜单上菜的数目 0<N<=16,<M<=N,<K<=12

    int ReqCount;        //饭团需要点的菜的数目

    int PeopleCount;     //就餐的人数

 

    int MeatDishCount;   //荤菜数目

    int SuDishCount;    //素菜数目

    int NaDishCount;    //辛辣菜数目

    int DanDishCount;   //清淡菜数目

}info;
 
 
// 判断结果是否满足点菜要求
void JudgeResult(const info *SelectMenuInfo,Dish *SaveData,Dish *SaveDataResult)
{
    int MeatTotal=0;
    int NaTotal=0;
    double TotalPrice=0;
    for (int j=1; j<=SelectMenuInfo->ReqCount; j++)
    {

       MeatTotal +=SaveData[j].MeatDish;

       NaTotal +=SaveData[j].NaDish;

       TotalPrice +=SaveData[j].Price;

    }
    // 满足点菜要求即荤菜数目与辛辣菜数目吻合
    if(SelectMenuInfo->MeatDishCount==MeatTotal&&SelectMenuInfo->NaDishCount==NaTotal)
    {
       double AverageCostCount=0;
       double AverageMinusNow=0;// 此次的消费与偏移量
 
       // 计算人均消费
       AverageCostCount=(TotalPrice*0.8)/SelectMenuInfo->PeopleCount;
       // 求出当次点菜人均消费偏移量

       AverageMinusNow =abs(AverageCostCount-12);

 
       // 如果消费偏移量比原来保存的小则更新
       if(AverageMinusNow<AverageMinus||Flag)
       {
           // 保存最接近人均元消费的信息

           Flag =false;

           // 更新人均消费与的偏移量与人均消费

           AverageCost =AverageCostCount;

           AverageMinus =AverageMinusNow;

 

           for (int j=1; j<=SelectMenuInfo->ReqCount; j++)

           {
              SaveDataResult[j]=SaveData[j];
           }
       }
 
    }
}
 
// 运用回逆法点ReqCount道菜,然后用JudgeResult是否满足要求
void GetDishes(int num, int pos,Dish *SaveData,const info *SelectMenuInfo,Dish *SaveDataResult,const Dish *SrcData)
{
    if (num == SelectMenuInfo->ReqCount)// 处理最后一个菜
    {

       for (int i=pos; i<SelectMenuInfo->MenuTotal; i++)

       {
           SaveData[num] = SrcData[i];
           // 判断结果是否满足要求
           JudgeResult(SelectMenuInfo,SaveData,SaveDataResult);
       }  
 
    }
    else // 如果处理的不是最后一个菜,应采用回溯方法以取得最优解
    {
       for (int i=pos; i<SelectMenuInfo->MenuTotal-SelectMenuInfo->ReqCount+num; i++)
       {
           SaveData[num] = SrcData[i];
           GetDishes(num+1, i+1,SaveData,SelectMenuInfo,SaveDataResult,SrcData);
       }
    }
}
 
/************************************************************************/
/* 从文件FilePath中读取菜单信息,将
/* 菜单上菜的数目、饭团需要点的菜的数目、就餐的人数、荤菜数目、素菜数目、

/*辛辣菜数目、清淡菜数目存入到SelectMenuInfo结构体中,将菜单信息通过DishMenu结构体返回                                                                   */

/************************************************************************/

DishReadDataFromFile(const char *FilePath,info *SelectMenuInfo)

{
    ifstream inFile("in.txt");
    if(inFile==NULL)
    {
       cerr<<" 打开文件失败" <<endl;
       return NULL;
    }
 
    inFile>>SelectMenuInfo->MenuTotal>>SelectMenuInfo->ReqCount>>SelectMenuInfo->PeopleCount;
    cout<<" 菜单上菜的数目:" <<SelectMenuInfo->MenuTotal<<endl;
    cout<<" 点的菜的数目:" <<SelectMenuInfo->ReqCount<<endl;
    cout<<" 就餐的人数:" <<SelectMenuInfo->PeopleCount<<endl;
    cout<<"++++++++++++++++++++++++++++++++"<<endl;
 

    Dish *DishMenu =new Dish[SelectMenuInfo->MenuTotal+1]; //菜单信息

 
    // 菜单信息
    int nPos=0;
    while(nPos<(SelectMenuInfo->MenuTotal))
    {
       inFile>>DishMenu[nPos].DishName;
       inFile>>DishMenu[nPos].Price;
       inFile>>DishMenu[nPos].MeatDish;
       inFile>>DishMenu[nPos].NaDish;

       cout<<DishMenu[nPos].DishName<<" "<<DishMenu[nPos].Price<<" "<<DishMenu[nPos].MeatDish<<" "<<DishMenu[nPos].NaDish<<endl;

       nPos++;
    }
 
    // 读取点菜信息
    inFile>>SelectMenuInfo->MeatDishCount;
    inFile>>SelectMenuInfo->SuDishCount;
    inFile>>SelectMenuInfo->NaDishCount;
    inFile>>SelectMenuInfo->DanDishCount;
 
    cout<<"++++++++++++++++++++++++++++++++"<<endl;
    cout<<" 荤菜数目:" <<SelectMenuInfo->MeatDishCount<<endl;
    cout<<" 素菜数目:" <<SelectMenuInfo->SuDishCount<<endl;
    cout<<" 辛辣菜数目:" <<SelectMenuInfo->NaDishCount<<endl;
    cout<<" 清淡菜数目:" <<SelectMenuInfo->DanDishCount<<endl;
 
    inFile.close();
    return DishMenu;
}
 
// 保存最后结果输出到文件DstFilePath

int SaveDataToFile(const char *DstFilePath,const info *SelectMenuInfo,const Dish* SaveDataResult)

{
    ofstream outFile(DstFilePath);
    if(outFile==NULL)
    {
       cerr<<" 创建文件失败" <<endl;

       return -1;

    }
    cout<<"++++++++++++++++++++++++++++++++"<<endl;
    cout<<" 最后结果:" <<endl;
 
    for (int j=1; j<=SelectMenuInfo->ReqCount; j++)
    {
       cout<<" 菜名:" <<SaveDataResult[j].DishName<<endl;
       outFile<<SaveDataResult[j].DishName<<endl;
    }
    cout<<" 人均消费:" <<AverageCost<<endl;
    outFile<<AverageCost<<endl;
 
    outFile.close();
 
    return 0;
}
 
int main(void)
{

    info *SelectMenuInfo=new info;

    char SrcFilePath[]="in.txt";
    char DstFilePath[]="out.txt";
 
    Dish *DishMenu=NULL;
 
    DishMenu=ReadDataFromFile(SrcFilePath,SelectMenuInfo);
 
    if(DishMenu==NULL)
    {
       cout<<" 获取文件信息失败" <<endl;

       return -1;

    }
 

    Dish *SaveDataResult=new Dish[SelectMenuInfo->ReqCount+1];   //最后点菜信息结果

    Dish *SaveData =new Dish[SelectMenuInfo->ReqCount+1];       //保存回逆过程中的点菜信息

 
    GetDishes(1,0,SaveData,SelectMenuInfo,SaveDataResult,DishMenu);
 
    int ret =SaveDataToFile(DstFilePath,SelectMenuInfo,SaveDataResult);
    if(ret!=0)
    {
       cout<<" 保存文件信息失败" <<endl;

       return -1;

    }
 
    delete SelectMenuInfo;
    delete[] SaveDataResult;
    delete[] SaveData;
 
    system("pause");
    return 0;
}

 
刚开始写的时候没有用结构体,也贴出来对比一下

 

#include <iostream>
#include <string>
#include <fstream>
#include <math.h>
using namespace std;
 

int MenuTotal=0; //菜单上菜的数目 0<N<=16,<M<=N,<K<=12

int ReqCount=0; // 饭团需要点的菜的数目
int PeopleCount=0; // 就餐的人数
 
int MeatDishCount=0;   // 荤菜数目
int SuDishCount=0;    // 素菜数目
int NaDishCount=0;    // 辛辣菜数目
int DanDishCount=0;   // 清淡菜数目
 
double AverageMinus=0; // 人均消费与的偏移量
double AverageCost=0; // 人均消费
bool    Flag=true;     // 满足条件日第一次偏移量标志
 
typedef struct 
{
    string DishName// 菜名

    int Price;        //价格

    int MeatDish;     //是否为晕菜

    int NaDish;      //是否为辛辣

}Dish,*pDish;
 

void GetDishes(int num, int pos,Dish *SaveData,Dish *SaveDataResult,const Dish *SrcData)

{
    if (num == ReqCount)// 处理最后一个菜
    {
       for (int i=pos; i<MenuTotal; i++)
       {
           SaveData[num] = SrcData[i];
 

           int MeatTotal=0;

           int NaTotal=0;

           double TotalPrice=0;

           for (int j=1; j<=ReqCount; j++)

           {

              MeatTotal +=SaveData[j].MeatDish;

              NaTotal +=SaveData[j].NaDish;

              TotalPrice +=SaveData[j].Price;

           }
           // 满足点菜要求即荤菜数目与辛辣菜数目吻合
           if(MeatDishCount==MeatTotal&&NaDishCount==NaTotal)
           {

              double AverageCostCount=0;

              double AverageMinusNow=0;//此次的消费与偏移量

              // 计算人均消费
              AverageCostCount=(TotalPrice*0.8)/PeopleCount;
              // 人均消费偏移量

              AverageMinusNow =abs(AverageCostCount-12);

              // 如果消费偏移量比原来保存的小则更新
              if(AverageMinusNow<AverageMinus||Flag)
              {
                  // 保存最接近人均元消费的信息

                  Flag =false;

                  // 更新人均消费与的偏移量与人均消费

                  AverageCost =AverageCostCount;

                  AverageMinus =AverageMinusNow;

 

                  for (int j=1; j<=ReqCount; j++)

                  {
                     SaveDataResult[j]=SaveData[j];
                  }
              }
           }
       }  
 
    }
    else // 如果处理的不是最后一个菜,应采用回溯方法以取得最优解
    {
       for (int i=pos; i<MenuTotal-ReqCount+num; i++)
       {
           SaveData[num] = SrcData[i];
           GetDishes(num+1, i+1,SaveData,SaveDataResult,SrcData);
       }
    }
}
 
int main(void)
{
    ifstream inFile("in.txt");
    ofstream outFile("out.txt");
 
    if(inFile==NULL)
    {
       cerr<<" 打开文件失败" <<endl;

       return -1;

    }
 
    if(outFile==NULL)
    {
       cerr<<" 创建文件失败" <<endl;

       return -1;

    }
 
    inFile>>MenuTotal>>ReqCount>>PeopleCount;
    cout<<" 菜单上菜的数目:" <<MenuTotal<<endl;
    cout<<" 点的菜的数目:" <<ReqCount<<endl;
    cout<<" 就餐的人数:" <<PeopleCount<<endl;
    cout<<"++++++++++++++++++++++++++++++++"<<endl;
 
    Dish *DishMenu =new Dish[MenuTotal+1]; // 菜单信息
    Dish *SaveData =new Dish[ReqCount+1];   // 点菜信息

    Dish *SaveDataResult=new Dish[ReqCount+1];        //最后点菜信息结果

 
    int nPos=0;
    while(nPos<MenuTotal)
    {
        inFile>>(DishMenu[nPos].DishName)>>(DishMenu[nPos].Price)>>(DishMenu[nPos].MeatDish)>>(DishMenu[nPos].NaDish);

       cout<<DishMenu[nPos].DishName<<" "<<DishMenu[nPos].Price<<" "<<DishMenu[nPos].MeatDish<<" "<<DishMenu[nPos].NaDish<<endl;

       nPos++;
    }
 
    // 读取点菜信息
    inFile>>MeatDishCount>>SuDishCount>>NaDishCount>>DanDishCount;
    cout<<"++++++++++++++++++++++++++++++++"<<endl;
    cout<<" 荤菜数目:" <<MeatDishCount<<endl;
    cout<<" 素菜数目:" <<SuDishCount<<endl;
    cout<<" 辛辣菜数目:" <<NaDishCount<<endl;
    cout<<" 清淡菜数目:" <<DanDishCount<<endl;
 
    inFile.close();
 
 
 
    GetDishes(1,0,SaveData,SaveDataResult,DishMenu);
 
    cout<<"++++++++++++++++++++++++++++++++"<<endl;
    cout<<" 最后结果:" <<endl;
 
    for (int j=1; j<=ReqCount; j++)
    {
       cout<<" 菜名:" <<SaveDataResult[j].DishName<<endl;
       outFile<<SaveDataResult[j].DishName<<endl;
    }
    cout<<" 人均消费:" <<AverageCost<<endl;
    outFile<<AverageCost<<endl;
 
    outFile.close();
 
    system("pause");
    return 0;
}

 输出结果:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值