3046. 足球
Description
众所周知,一只足球队由11球员组成,其中有一名守门员和一名队长。 现在,有22人组成的一个候选名单,从中要选出11人参加比赛。选拔规则如下: 首先提供一个阵型,例如,4-4-2。第一个4表示有4名后卫,第二个4表示有4名中场,第三个2表示有2名前锋。当然,还有一个位置就是留给守门员的。 每个人都有自己唯一能打的位置(前锋、中场、后卫、守门员)。在每个位置上,以球员的编号为关键字,从小到大依次选取。 选出球队后还要选出队长。队长是球队中参加比赛次数最多的球员。如果有并列,取编号较大的球员做队长。
Input Format
前22行每行按如下格式表示出一名球员的信息:
Number Name Role year1-year’1 year2-year’2 …
整数Number(<=100)是该球员编号。字符串Name(length<=20)是该球员名字。字符Role是该球员所能打的位置(S前锋、M中场、D后卫、G守门员)。每一对yeari-year’i(yeari<=year’i) 表示该球员效力的时间段,例如2001-2002表示该球员效力了两年2001年和2002年。至少有1对年份,最多20对年份。年份是一个四位数。保证任意两段年份不会重叠。球员的编号在球队中是唯一的。
第23行给出一个阵型,例如4-4-2。保证阵型有且仅有3个正整数组成,且和等于10。例如,4-3-2-1是不合法的。
Output Format
输出选出的11名球员,每一行包括球员编号,姓名,场上所打位置。之间用一个空格隔开。球员按守门员、后卫、中场、前锋的顺序排序,相同位置按编号从小到大排序。如果一名球员是队长,那么无论他打什么位置,都放在序列的第一个。如果无法找出11个满足条件的球员,输出“IMPOSSIBLE TO ARRANGE”。
Sample Input
9 PlayerA M 2000-2001 2003-2006
2 PlayerB M 2004-2006
10 PlayerC D 2001-2005
1 PlayerD D 2000-2001 2002-2004
11 PlayerE S 2003-2006
8 PlayerF M 2005-2006
22 PlayerG S 2005-2006
25 PlayerH G 2000-2001 2002-2003 2005-2006
6 PlayerI D 2003-2006
26 PlayerJ D 2003-2004 2000-2001
18 PlayerK M 2003-2004
19 PlayerL M 2000-2001 2003-2006
7 PlayerM S 2003-2006 1999-2001
21 PlayerN S 2003-2006
13 PlayerO S 2005-2006
15 PlayerP G 2001-2006
14 PlayerQ D 2003-2004
5 PlayerR S 2000-2005
20 PlayerS G 2000-2002 2003-2003
12 PlayerT M 2004-2005
3 PlayerU D 2000-2005
4 PlayerZ M 2001-2004
4-4-2
Sample Output
7 PlayerM S
15 PlayerP G
1 PlayerD D
3 PlayerU D
6 PlayerI D
10 PlayerC D
2 PlayerB M
4 PlayerZ M
8 PlayerF M
9 PlayerA M
5 PlayerR S
Limits
Time limit: 1000ms, memory limit: 50000kb.
===============================================================
题解正文
===============================================================
题目分析:
首先我们要知道这道题目给了什么信息:
这是张由22个球员构成的表。
每个主球运动员都有 编号(唯一)、名字(没有用)、位置(D M S G)、年份(这个年份纯粹是搞出来糊弄人的,我们只要通过一定手段算出来到底有多少年即可)
这题很好的地方是年份一定是四位数并且一定是长度为9的字符串:XXXX-XXXX,这个非常便于我们计算该运员干了多少年,干的年份越久表示参加的比赛越多 = =。
输出的要求其实也很简单,满足阵型是首要条件,接下来是选取相应的人,注意到同位置选取编号小的;
选队长时优先选年份多的,再次是编号大的(和上面不同)。
算法实现:
输入
考虑到运动员这一独立的对象,又懒得写类,于是用struct来构造一个player,这个struct叫ply
struct ply{ int num; //编号 string name; //名字 char pst; //位置 int years; //年份 bool used; //是否已经被选取,必要性不太大,保险起见而已 }players[22],team[11]; //左边是备选的22个备胎,右边是被选中的11个孩子
上面提到的pst其实用枚举类型更好,直接给那几个位置赋G0 D1 M2 S3 这样输出时排列非常方便
输入流处理:
void init() { cin >> players[0].num; //这里可以看到我编号是额外处理的,这是因为读取年份时为了简便 string tmp; //不得不多读一个字符串,导致下一个球员的编号被读入了tmp中 for(int i = 0; i < 22; ++i) { cin >> players[i].name //直接存就好了 >>players[i].pst; players[i].years = 0; while(cin >> tmp && tmp.length() == 9) //这就是为了及时停下来,但无可避免地 { //读取了下一个球员的编号 int a, b; a = 1000 * (tmp[0] - '0') + //计算年份 100 * (tmp[1] - '0') + 10 * (tmp[2] - '0') + (tmp[3] - '0'); b = 1000 * (tmp[5] - '0') + 100 * (tmp[6] - '0') + 10 * (tmp[7] - '0') + (tmp[8] - '0'); players[i].years += (b - a) + 1; //注意这个加一,小学常见的应用题陷阱 } if(i < 21) players[i+1].num = (int)atof(tmp.c_str());//string直接转成int players[i].used = 0; //初始化 } sort(players, players + 22, cmp1); //排序优先位置升序,其次编号升序 cin >> tmp; D = tmp[0] - '0'; M = tmp[2] - '0'; S = tmp[4] - '0'; }
详细讲一下cmp的使用,我使用了三个cmp,分别有不同的用处,他们极大地维护了代码的简洁和准确
inline bool cmp1(ply a, ply b) { //优先位置升序,其次编号升序 if(a.pst == b.pst) else return a.num < b.num; else return a.pst < b.pst; } //选队长专用 inline bool cmp2(ply a, ply b) { //优先年份,年份一样按大序号优先 if(a.years == b.years ) return a.num > b.num; else return a.years > b.years; } //最后除了队长之外的人进行排序 inline bool cmp3(ply a, ply b) { if(a.pst == 'G')return 1;//这两条确保后卫排在最前面 if(b.pst == 'G')return 0; else//恰好利用了ascii中D < M < S 这一原则 不过如果输出顺序不按GDMS 我们也可以通过 //enum来安排顺序值 if(a.pst == b.pst) return a.num < b.num; else return a.pst < b.pst; }
选拔
选拔就比较简单了,主要是用了一个变量t来引导球员储存到team中并且计算一共有多少球员满足要求,当且仅当t==11时满足要求,因此可以直接用t来判断是否有解,我第一次提交就是忘记考虑无解的情况了
另外输入的时候读取了四个位置所要求的值(当然G默认为1)通过while循环达到读取的目的,不会漏掉也不会多取。
具体请看最终代码
输出
输出很简单了。如果有解就对team数组进行排序,然后打印出来。无解就输出那句话即可。
代码送上,有很多不足,大家看看就好~欢迎讨论
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include<stdlib.h>
#include<stdio.h>
using namespace std;
struct ply{
int num;
string name;
char pst;
int years;
bool used;
}players[22],team[11];
int D, M, S, G, L;
bool flag = 1;
inline bool cmp1(ply a, ply b)
{
if(a.pst == b.pst)
{
if(a.num == b.num)
{
if(a.years == b.years) return a.name < b.name;
else return a.years > b.years;
}
else return a.num < b.num;
}else return a.pst < b.pst;
}
inline bool cmp2(ply a, ply b)
{
if(a.years == b.years ) return a.num > b.num;
else return a.years > b.years;
}
inline bool cmp3(ply a, ply b)
{
if(a.pst == 'G')return 1;
if(b.pst == 'G')return 0;
else
if(a.pst == b.pst) return a.num < b.num;
else return a.pst < b.pst;
}
void init()
{
cin >> players[0].num;
string tmp;
for(int i = 0; i < 22; ++i)
{
cin >> players[i].name
>>players[i].pst;
players[i].years = 0;
while(cin >> tmp && tmp.length() == 9)
{
int a, b;
a = 1000 * (tmp[0] - '0') +
100 * (tmp[1] - '0') +
10 * (tmp[2] - '0') + (tmp[3] - '0');
b = 1000 * (tmp[5] - '0') +
100 * (tmp[6] - '0') +
10 * (tmp[7] - '0') + (tmp[8] - '0');
players[i].years += (b - a) + 1;
}
if(i < 21) players[i+1].num = (int)atof(tmp.c_str());
players[i].used = 0;
}
sort(players, players + 22, cmp1);
cin >> tmp;
D = tmp[0] - '0';
M = tmp[2] - '0';
S = tmp[4] - '0';
}
void select()
{
int t = 0;
for(int i = 0; i < 22; ++i)
{
while(D && players[i].pst == 'D')
{
team[t++] = players[i];
++i, --D;
}
if(players[i].pst == 'G')
team[t++] = players[i];
while(players[i].pst == 'G')++i;
while(M && players[i].pst == 'M')
{
team[t++] = players[i];
++i, --M;
}
while(S && players[i].pst == 'S')
{
team[t++] = players[i];
++i, --S;
}
}
if(t == 11)
{
sort(team, team + 11, cmp2);
sort(team + 1, team + 11, cmp3);
}else flag = 0;
}
int main()
{
init();
select();
if(flag)
for(int i = 0; i < 11; ++i)
cout<<team[i].num<<" "<<team[i].name<<" "<<team[i].pst<<endl;
else cout<<"IMPOSSIBLE TO ARRANGE"<<endl;
}