第一题(牛车):
题意:
一些牛要开车上高速公路,第i头牛的车速为si,有m条高速公路,如果一条车道上前面有x头牛,那现在这头牛的速度就会降低d*x,我们现在要求最多能有多少头牛能上高速。
思路:
先让他们的速度排序,因为最好是速度慢的先上高速比较好,然后从1到n头牛枚举,从1到m条车道枚举,如果这头牛可以上这条车道,我们就用一个数组统计这条车道上牛的数量,然后让ans+1。
代码:
#pragma G++ optimize (2)
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,d,l,s[50010],c[50010],ans,s1,t;
int max(int x,int y){return x>y?x:y;}
int main()
{
scanf("%d%d%d%d",&n,&m,&d,&l);
for (int i=1;i<=n;i++)
scanf("%d",&s[i]);
sort(s+1,s+n+1);//快速排序
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
{
t=s[i]-(c[j]*d);//c[j]为第j条车道上牛的数量
s1=max(t,0);//题目中说了速度最小为0
if (s1>=l) {c[j]++;ans++;break;} //如果速度满足条件就进行统计
}
}
printf("%d",ans);
}
第二题(危险系数):
题意:
按照给出的访问次序ai去探索岛屿,每个岛屿之间的危险系数是f[i][j],求我们按照这个访问次序去访问岛屿最少的危险系数。(我们的访问次序可以不连续,但要包含ai)。
思路:
其实就是先求出两个岛屿间最少的危险系数,可以用Floyd求,然后再按照ai去累加最少的危险系数就好了。
代码:
#pragma GCC optimize (2)
#include<cstdio>
int n,m,a[10010],f[110][110],ans;
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
scanf("%d",&a[i]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
scanf("%d",&f[i][j]);//我这里没判断f[i][j]为0的情况,之前判断了就错了
}
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (i!=k&&k!=j&&i!=j&&f[i][k]+f[k][j]<f[i][j]) f[i][j]=f[i][k]+f[k][j];//Floyd
for (int i=1;i<=m-1;i++)
ans+=f[a[i]][a[i+1]];//按照ai去累加
printf("%d",ans);
}
第三题(前缀转后缀):
题意:
给出一个只含有+-符号和数字的前缀表达式,求出它的后缀表达式。
思路:
我们可以把前缀表达式变成树的形式,然后再用后序遍历输出后缀表达式,树的话就是符号每次读入,如果这个为符号,我们就读入它的孩子,后序遍历就是左右根的遍历。
代码:
#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
char s[1111];
void read(int x)
{
char c;
cin>>c;
if (c>'9'||c<'0')//如果是符号就读入它的孩子
{
s[x]=c;
read(2*x);//左孩子
read(2*x+1);//右孩子
}else s[x]=c;//如果不是符号我们就直接存下来
}
void tree(int x)
{
if (s[2*x]!='A') tree(2*x);//如果它有左孩子就遍历左的
if (s[2*x+1]!='A') tree(2*x+1);//如果它有右孩子就遍历右的
printf("%c ",s[x]);//左右根,左右遍历完了我们就可以输出根了
}
int main()
{
freopen("j4.in","r",stdin);
freopen("j4.out","w",stdout);
for (int i=1;i<=1111;i++) s[i]='A';//A表示没有
read(1);
tree(1);
}
第四题(游戏):
题意:
有两个人在玩游戏,有四种材料,每次他们都可以把其中的材料放进反应堆反应,有五种反应情况,每次反应都是会使材料化为乌有,他们玩n局游戏,每次给出四种材料的初值,当某个人选不了材料进行反应他就输了,他们都是用最好的方法去玩的。
思路:
用记忆化搜索,每次的材料如果可以反应我们就从这里为起点搜,如果没有材料进行反应了我们就返回1,1是先手赢,因为1先拿,这时轮到2拿,没有材料了,所以就是1赢了,如果怎样都不能使2输,那就返回2赢,用f记录当前材料是谁能赢。
代码:
#pragma GCC optimize(2)
#include<cstdio>
int n,a,b,c,d,v[6][5],f[61][61][61][61];
int dfs(int A,int B,int C,int D)
{
if (f[A][B][C][D]) return f[A][B][C][D];//这里是记录的地方,可以避免过多的搜索
for (int i=1;i<=5;i++)
{
if (A>=v[i][1]&&B>=v[i][2]&&C>=v[i][3]&&D>=v[i][4])//v表示每次反应会消耗的对应材料
{
if (dfs(A-v[i][1],B-v[i][2],C-v[i][3],D-v[i][4])==2)
{f[A][B][C][D]=1;
return 1;}
}
}
f[A][B][C][D]=2;
return 2;
}
int main()
{
freopen("j5.in","r",stdin);
freopen("j5.out","w",stdout);
scanf("%d",&n);
v[1][1]=2;v[1][2]=1;v[1][4]=2;v[2][1]=1;v[2][2]=1;v[2][3]=1;v[2][4]=1;v[3][3]=2;v[3][4]=1;v[4][2]=3;v[5][1]=1;v[5][4]=1;
for (int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
if (dfs(a,b,c,d)==2) printf("Roland\n");//2是后手,Patrick是先手
else printf("Patrick\n");
}
}