PAT(甲级)2011年秋仿真卷
发现PAT练习的网站上可以购买往年的真题试卷进行练习,购买时光机以后还可以看到考试的实时榜单,和当时现场考试的考生同场竞技。
最近开始为准备9月的PAT考试复习刷题,争取能够取得理想的成绩!
A World Cup Betting (20 分)
【解题思路】
算是签到题,没什么技术含量。
【满分代码】
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
double a,b,c,odds=1;
for(int i=1;i<=3;i++)
{
scanf("%lf%lf%lf",&a,&b,&c);
if(a>b&&a>c)
{
printf("W ");
odds*=a;
}
else if(b>a&&b>c)
{
printf("T ");
odds*=b;
}
else if(c>a&&c>b)
{
printf("L ");
odds*=c;
}
}
printf("%.2f\n",(odds*0.65-1)*2);
return 0;
}
B The Best Rank (25 分)
【解题思路】
很显然这是一道排序题,我们用结构体存数据,使用cmp函数进行排序。要注意的是,这道题细节很多。
比如当两个人分数相同时,排名的值相同,比如如果有4个人,中间2个人当前课程的分数并列,那么他们当前课程的排名分别是1,2,2,4。
另外要注意在选取最优排名时,各门科目的优先级,即A > C > M > E。为方便起见,我们数组下标1到3分别表示C、M、E三门课,下标0计算平均分A。
排序的时候用到一个小技巧,因为我们需要按照不同科目进行排序,统计名次,我们用一个全局变量sub,这样我们修改sub的值,使用cmp函数就能按照对应科目进行排序了。
最后我们使用一个map来记录每个学号是否存在,同时可以记录最终这个学号在结构体数组当中的位置。查询时,若输入的学号存在,输出答案即可,否则输出N/A。
【满分代码】
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
using namespace std;
struct node
{
string s;
int grade[4],rank[4],best;
char ans;
}stu[2005];
int sub=0;
bool cmp(node a,node b)
{
return a.grade[sub]>b.grade[sub];
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
{
cin>>stu[i].s>>stu[i].grade[1]>>stu[i].grade[2]>>stu[i].grade[3];
stu[i].grade[0]=stu[i].grade[1]+stu[i].grade[2]+stu[i].grade[3];
}
for(int i=0;i<4;i++)
{
sub=i;
sort(stu,stu+n,cmp);
stu[0].rank[i]=1;
for(int j=1;j<n;j++)
{
if(stu[j].grade[i]==stu[j-1].grade[i])
stu[j].rank[i]=stu[j-1].rank[i];
else
stu[j].rank[i]=j+1;
}
}
map<string,int> mp;
for(int i=0;i<n;i++)
{
mp[stu[i].s]=i;
int best=0,temp=2005;
for(int j=0;j<4;j++)
{
if(stu[i].rank[j]<temp)
{
temp=stu[i].rank[j];
best=j;
}
}
stu[i].best=temp;
if(best==0)
stu[i].ans='A';
else if(best==1)
stu[i].ans='C';
else if(best==2)
stu[i].ans='M';
else
stu[i].ans='E';
}
string s;
for(int i=0;i<m;i++)
{
cin>>s;
if(mp.count(s))
cout<<stu[mp[s]].best<<" "<<stu[mp[s]].ans<<endl;
else
cout<<"N/A"<<endl;
}
return 0;
}
C Battle Over Cities (25 分)
【解题思路】
给出一个无向图,需要我们求的是,去掉某个点后,使得剩下的所有点连通,至少需要添加几条边。
显然,我们只要求去掉那个点之后,一共有几个连通分量,需要添加的最少边数即为连通分量数-1。
这道题和3月14日的牛客网训练联盟热身训练赛第二场的F Interstellar Love题差不多。
采用并查集或者DFS都能够求得连通分量数,下面分别给出两种做法的代码。
【满分代码1 并查集】
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=1010;
vector<int> G[maxn];//邻接表
int n,m,k,a,b,c,p[maxn],vis[maxn];
int find(int x)
{
return p[x]==x?x:p[x]=find(p[x]);
}//并查集
void unio(int a,int b)
{
int x=find(a),y=find(b);
if(x!=y) p[x]=y;
}
void init()
{
for(int i=1;i<=n;i++)
{
p[i]=i;
vis[i]=0;
}
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m>>k;
for(int i=0;i<m;i++)
{
cin>>a>>b;
G[a].push_back(b);
G[b].push_back(a);
}
for(int t=0;t<k;t++)
{
cin>>c;
init();
for(int i=1;i<=n;i++)
{
int size=G[i].size();
for(int j=0;j<size;j++)
{
if(i!=c&&G[i][j]!=c)
unio(i,G[i][j]);
}
}
int ans=0;
/*
for(int i=1;i<=n;i++)
if(i!=c) find(i);//注意是find(i)不是p[i]
sort(p+1,p+n+1);
for(int i=1;i<=n;i++)
if(p[i]!=p[i-1]&&p[i]!=c)
ans++;
cout<<ans-1<<endl;
*/
for(int i=1;i<=n;i++)
{
if(i==c) continue;
int fa=find(i);
if(!vis[fa])
{
ans++;
vis[fa]=1;
}
}
cout<<ans-1<<endl;
}
return 0;
}
【满分代码2 DFS】
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int num=2000005;//注意:链式前向星,无向图,开两倍(最大边数1000*1000的两倍)!!!
int n,m,k,a,b,c,ans=0;//ans为连通分量数量
struct edge
{
int to,next;
}edge[num];
int cnt,head[num];
void init()
{
for(int i=0;i<num;i++)
{
edge[i].next=-1;
head[i]=-1;
}
cnt=0;
}
void addedge(int u,int v)
{
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}//链式前向星存图
int vis[1010],flag;
void dfs(int x)
{
for(int i=head[x];i!=-1;i=edge[i].next)
if(edge[i].to!=c)
{
if(vis[edge[i].to]==0)
{
vis[edge[i].to]=1;
dfs(edge[i].to);
}
}
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m>>k;
init();
for(int i=1;i<=m;i++)
{
cin>>a>>b;
addedge(a,b);
addedge(b,a);
}
for(int i=1;i<=k;i++)
{
memset(vis,0,sizeof(vis));
ans=0;
cin>>c;
for(int i=1;i<=n;i++)
{
if(vis[i]==0&&i!=c)
{
vis[i]=1;
ans++;
dfs(i);
}
}
cout<<ans-1<<endl;
}
return 0;
}
D Waiting in Line (30 分)
【解题思路】
很显然这是一道模拟题,按照题意用队列模拟即可。
这种题目没有什么要用到的算法,就是有一定的代码量,且细节较多,代码当中做了注释。
如果正式考试最后一题考这种类型其实也挺好,静下心来一步步分析,遇到困难总是有办法解决的。
因为PAT考试是可以实时看到得分的,哪怕一开始没有拿到满分,也可以通过不断修改来提高,三个小时的时间相对而言也比较充裕。希望能够通过这段时间的练习,取得一个不错的成绩。
【满分代码】
#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
int n,m,k,q,a,t[1005],ans[1005];
struct node
{
int poptime,endtime;//第一个人出队时间,最后一个人结束时间
queue<int> que;//队伍
}w[25];//窗口
int main()
{
int index=0;//当前处理的客户编号
cin>>n>>m>>k>>q;
for(int i=0;i<k;i++)
cin>>t[i];
for(int i=0;i<n;i++)
w[i].poptime=w[i].endtime=0;//初始化时间
for(int i=0;i<min(n*m,k);i++)
{
w[index%n].que.push(index);
w[index%n].endtime+=t[index];
if(index<n)
w[index].poptime=t[index];
ans[index]=w[index%n].endtime;
index++;
}
for(;index<k;index++)
{
int temp=0,mint=1999999999;
for(int i=0;i<n;i++)
{
if(w[i].poptime<mint)
{
mint=w[i].poptime;
temp=i;
}
}//找到最快空出位置的窗口排队,如果同时空出则默认在前的窗口优先
w[temp].que.pop();
w[temp].que.push(index);
w[temp].poptime+=t[w[temp].que.front()];
w[temp].endtime+=t[index];
ans[index]=w[temp].endtime;
}
for(int i=0;i<q;i++)
{
cin>>a;
a--;//下标从0开始
if(ans[a]-t[a]<540)
printf("%02d:%02d\n",ans[a]/60+8,ans[a]%60);//注意时间加上8点
else
printf("Sorry\n");
}
return 0;
}