1.无聊的游戏
由题意可得,这道题只需要村模拟即可,就是稍微复杂里一点
1.循环枚举每一个没死的同学,找到与该同学最近的一个非自身且没有死的同学,然后将其杀掉(标记一下)即可。
2.因为给的同学的位置是坐标系的坐标,所以求最近距离是要用上勾股定理,即行列的绝对值之差的平方之和。
3.如果一次循环没有把剩下的杀死,那就再循环一次即可。
4.如果在模拟的过程中总数为1,那么就找到唯一生存的同学并且输出以及退出循环。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int students;
struct Cristiano_Ronaldo
{
int x,y,die;
}student[3000]={};//x,y记录坐标;die记录该学生是否死掉
inline int find_the_shortest_student(int student_number)//找到与第student_number个学生最近的学生
{
double shortest_distance=999999999.0;
int shortest_student_number=0;
for (int i=1;i<=students;i++)
if (i!=student_number&&student[i].die==0)//学过没有死并且不是自己本身
{
double distance=sqrt(pow(abs(student[student_number].x-student[i].x),2)
+pow(abs(student[student_number].y-student[i].y),2));
if (shortest_distance>distance)
{
shortest_distance=distance;
shortest_student_number=i;
}//勾股定理求最小值
}
return shortest_student_number;
}
inline int find_the_only_one_student()//找到唯一生存的学生
{
for (int i=1;i<=students;i++)
if (student[i].die==0) return i;
}
int main()
{
cin>>students;
if (students==0)
{
cout<<0;
return 0;
}
for (int i=1;i<=students;i++)
cin>>student[i].x>>student[i].y;
for (int i=1;i<=3000;i++)
student[i].die=0;//标记未死亡
int sum=students;
while (true)
{
for (int i=1;i<=students;i++)
{
if (sum==1)//如果只剩下一个学生
{
cout<<find_the_only_one_student();
return 0;
}
if (sum>1&&student[i].die==0)//如果该学生没死并且总数大于1
{
int willdie=find_the_shortest_student(i);//找到最近的学生
student[willdie].die=1;//杀死
sum--;
}
}
if (sum==1)
{
cout<<find_the_only_one_student();//找到唯一生存的学生
return 0;
}
}
return 0;
}
2.食堂的座位
模拟条件:
1.如果该座位是单人的,那么优先考虑左半部分,避免对后面产生影响,如果没有再考虑右边
2.如果是双人座位的左边,那么就判断左边有没有位置;如果是双人座位的右边,那么就判断座位的右边有没有位置。
3.因为数据较少,用二维数组uesd[i][j]来表示i和j之间的位置是否被坐。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int seats,used[100][100]={},double_seat=-1,ans=0;
char seat[1000]={};
cin>>seats;
for (int i=1;i<=seats;i++)
cin>>seat[i];
for (int i=1;i<=seats;i++)
{
if (seat[i]=='S')
{
if (used[i-1][i]==0) used[i-1][i]=1;
else if (used[i][i+1]==0) used[i][i+1]=1;
else ans++;
}//判断是单人座位的情况
if (seat[i]=='L')
{
double_seat=(double_seat+1)%2;//该变量控制的是双人座位的方向,即左边或右边
if (double_seat==0)
if (used[i-1][i]==0) used[i-1][i]=1;
else ans++;
else
if (used[i][i+1]==0) used[i][i+1]=1;
else ans++;
}//判断双人座位的情况
}
cout<<seats-ans;
return 0;
}
3.括号表达式的值
1.因为由题意可得,括号是平衡的,因此可以用括号匹配来做,找出与每一个左括号所匹配的右括号。
2.括号匹配的方法如下:用栈记录左括号的地址,每次匹配到一个右括号就记录栈顶所匹配的右括号的地址,并出栈,如此反复操作即可。
3.接着,就可以dfs了,先dfs(1,n),然后接着递归就可以。
递归过程如下:
a.如果它由多个平衡的括号组成,就递归第一个平衡的括号和剩下部分。
b.如果有且只有一对不嵌套的括号,返回值为2.
c.如果只有一对平衡且带有嵌套的括号,去掉头和尾接着递归,并且结果乘2即可。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const long long Mod=12345678910;
struct Cristiano_Ronaldo
{
int num,next;//num记录0和1,next记录匹配的右括号
}a[100000]={};
long long dfs(long long l,long long r)//dfs递归
{
long long ans=0;
if (a[l].next<r) ans=(ans+((dfs(l,a[l].next)%Mod)+(dfs(a[l].next+1,r)%Mod)%Mod))%Mod;//上述条件a
if (l+1==r) ans=(ans+1)%Mod;//上述条件b
if (a[l].next==r&&l+1<r) ans=(ans+2*(dfs(l+1,r-1)%Mod)%Mod)%Mod;//上述条件c
return ans;
}
int main()
{
long long n,top=0,st[100000]={};
cin>>n;
for (int i=1;i<=n;i++)cin>>a[i].num;
for (int i=1;i<=n;i++)
{
if (a[i].num==1) a[st[top]].next=i,top--;
if (a[i].num==0) st[++top]=i;
}//进行括号匹配
cout<<dfs(1,n);
return 0;
}
4.加油问题
1.因为数据没有排序,应按照地点进行排序。
2.排序后,要使加油费最小,用单调队列来维护每一个加油站的加油费和每一个加油站作加的油,令最便宜的油在对头即可。
3.因为要使车能达到终点,没到一个站都要把油加满,如果加的油比队尾的油要便宜,那么就把队尾去掉,直到前面的油比它大或者队列为空即可。
4.每次要用油的时候就从对头取油用,因为是最便宜的。
5.因为一开始已经拥有的油是不用钱的,说宜价格标记为0即可。
Q:这么反复将油加满不会对结果产生影响吗?因为加了很多没必要的油啊,那么结果不是会更高吗?
A:不会,因为队列只是用来控制可用的且最便宜的油的数量,最后用多少要看你在对头去多少油,因此给加满油的油不一定会用完,而是取多少用多少,最终的结果也只是和你取得油量有关。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int head=1,tail=1,ans=0;
struct jgt
{
int x,y;
}a[100000]={};
bool cmp(jgt xx,jgt yy)
{
return (xx.x<yy.x);
}
struct que
{
int p,h;//p=price,h=have
}q[100000]={};
void go(int x)
{
int s=x;
while (true)
{
if (s<q[head].h)//如果距离小于存油量
{
q[head].h-=s;//减少存油量
ans+=q[head].p*s;// 将用去的油乘这个油的价格存入总花费
return;
}
else//如果大于存油量
{
s-=q[head].h;//当该油量用完时 总路程也减少
ans+=q[head].p*q[head].h;//算花费
head++;//去对头
}
}
}
int pre_sum(int h,int t)//查找h到t区间的油量之和
{
int sum=0;
for (int i=h;i<=t;i++)
sum+=q[i].h;
return sum;
}
int main()
{
int n,g,b,d;
cin>>n>>g>>b>>d;
for (int i=1;i<=n;i++)
cin>>a[i].x>>a[i].y;
sort(a+1,a+n+1,cmp); //按照地点排序
q[1].p=0;
q[1].h=b;//把原有油进队
for (int i=1;i<=n;i++)
{
if (g<a[i].x-a[i-1].x)//如果两点间的距离比所能存储的容量大的话无解
{
cout<<-1;
return 0;
}
go(a[i].x-a[i-1].x);//走到下一个点,括号内表示走的距离
while (a[i].y<q[tail].p&&head<=tail)
tail--;//如果要新加入的元素的价格比队尾要小,切队列不为空
q[++tail].p=a[i].y;//储存价格
q[tail].h=g-pre_sum(head,tail-1);//储存所能存储的油量
}
if (g<d-a[n].x)
cout<<-1;
else
go(d-a[n].x);//从最后一个点走到终点
cout<<ans;
return 0;
}