AI GOD:1013: 小英的咖啡厅

http://118.190.162.167/p1013.html

 

题目描述

小英开了一家咖啡厅,和他的基友们做服务员。每个人不能在咖啡厅服务自己,因此如果某个人想来咖啡厅喝咖啡时正好赶上自己值班,就会变得很尴尬了。为此,小英决定和他的基友们轮班,使这种情况不会发生。现在小英已经知道了咖啡厅接下来的客人名单,客人们到达咖啡厅有严格的先后顺序,同一时间只有一位客人需要服务。你帮助小英找到需要换班次数最少的一种排班方法。

数据范围

1 < T <= 10.

对于小数据, 0 < S, C < 1000.

 

对于大数据, 0 < S, C < 10 0000.

输入描述

第1行,一个整数T,代表共有T组数据。

第2行,一个整数S,代表服务员数量。

接下来的S行是服务员的名字,名字中可能含有空格。

第S+3行,一个整数C,代表客人数量。

 

接下来的C行是客人的名字,其中可能包括服务员的名字,名字中可能含有空格。

输出描述

对于每组数据,输出一行,包含一个整数,代表最少所需的换班数。

样例输入(精确内容)

12Small EightSmall Five5Small EightBurningZhouSmall Fivezmsj
        

样例输出(精确内容)

1
        

提示

样例中最优的排班方式是先由 Small Five 值班直到他想需要服务时再换到Small Eight。

 

解题思路:首先,对输入的客人数据进行处理,将客人数组中的服务员按顺序摘取出来,其他信息舍去(普通客人不影响排班)。其次以服务员数组为纵坐标,从客人信息中摘取出来的服务员数据为横坐标,生成一张表。

 
                                                   
                                                                      表1                                                                                                        值班顺序
 
          
 
       服务生冲突的地方置1,不冲突的置0,此时将该问题转化成了迷宫问题,可用DFS方法来求的结果(答案貌似没有问题,但超时了)。或者可以使用动态规划的方法来做:新生成一个DP数组,DP表对应位置表示换班次数,从表一的第一行为0的位置开始,进行DP数组补全。
     
       针对DP某一位置(i,j),查找对应的表1 的(i,j)位置,当表1对应位置值为1 时,置DP表对应位置为MAX(MAX值自己定义,起标识作用),当表1对应的位置为0 ,此时需要查看DP表的第(i-1,j)位置的值。若值为MAX,则DP表的第(i,j)处值为DP表中第i-1行中的最小值+1(需要从别的列跳过来),若值不为MAX,则DP表的第(i,j)处值为DP表中第(i-1,j)的值(直接继承下来,不需要从别的列跳过来)。最后取DP表最后一行的最小值。
 
                                                                                          
                                                                                                                       DP 表
代码:
由于代码大小限制,对DP表只用两行进行迭代
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<vector>
#include<algorithm>
#define MAX 10000
using namespace std;

int Min(int *p,int len)
{
    int num=MAX;
    for(int i=0;i<len;i++)
    {
        if(p[i]<num)num=p[i];
    }
    return num;
}

int Map[2][100000]; //代码大小限制,只用两行迭代
int main()
{
    int num,num_e,num_g;
	//freopen("input.txt","r",stdin);
	cin>>num;
	while(num--)
	{
        string str;
        vector<string>employee;
        vector<string>guest;
		cin>>num_e;
		cin.ignore();
		while(num_e--)
        {
            getline(cin,str);
            employee.push_back(str);
        }
        cin>>num_g;
        cin.ignore();
        while(num_g--)
        {
            getline(cin,str);
            for(int i=0;i<employee.size();i++)
            {
                if(str==employee[i])
                {
                    guest.push_back(str);
                    break;
                }
            }
        }
        memset(Map,0,sizeof(Map));
        for(int i=0;i<employee.size();i++) //动态规划表初始化
        {
            if(employee[i]==guest[0])
                Map[0][i]=MAX;
        }
        for(int i=1;i<guest.size();i++)
        {
            for(int j=0;j<employee.size();j++)
            {
                if(employee[j]==guest[i])
                {
                    Map[i%2][j]=MAX;
                }
                else
                {
                    if(Map[(i-1)%2][j]==MAX){Map[i%2][j]=Min(Map[(i-1)%2],employee.size())+1;}
                    else {Map[i%2][j]=Map[(i-1)%2][j];}
                }
            }
        }
        /*for(int i=0;i<hang;i++)
        {   for(int j=0;j<employee.size();j++)
                cout<<Map[i][j];
            cout<<endl;
        }*/
        cout<<Min(Map[(guest.size()-1)%2],employee.size())<<endl;
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值