7-1绿色围栏(模拟)
本文已参与「新人创作礼」活动,一起开启掘金创作之路。
题目链接:PTA | 程序设计类实验辅助教学平台
样例输入:
14 5 2 1 1 4 3 5 2 6 -1 4 0 2 -1 0 样例输出:
0 0 2 1 5 3 6 -1 2 0 分析:第一个需要注意的就是他给的输入输出并不是直接给出点坐标,但是容易发现的一个地方就是,第i个给出的点有两种情况,如果i是奇数,那么给出的就是纵坐标,否则就是横坐标,假如给出的是纵坐标,那么这个点的横坐标和上一个点的横坐标就是相同的,如果给出的是横坐标,那么这个点的纵坐标和上一个点的纵坐标就是相同的。处理完输入之后就是一个简单的模拟了,需要注意的一个坑点就是如果最后恰好到(0,0)那么不用再进行输出,这个地方需要特殊判断一下。
下面是代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int N=1e4+10;
int x[N],y[N];
int main()
{
int n,l;
cin>>n>>l;
for(int i=1;i<=n;i++)
{
if(i&1)
{
scanf("%d",&y[i]);
x[i]=x[i-1];
}
else
{
scanf("%d",&x[i]);
y[i]=y[i-1];
}
}
x[n+1]=0;y[++n]=0;
int X=0,Y=0,ll=l;
printf("0 0");
for(int i=1;i<=n;i++)
{
int t=abs(x[i]-X)+abs(Y-y[i]);
while(t>ll)
{
if(X==x[i])
{
if(y[i]-Y>0)
{
t-=ll;
Y+=ll;
ll=l;
}
else
{
t-=ll;
Y-=ll;
ll=l;
}
}
else
{
if(x[i]-X>0)
{
t-=ll;
X+=ll;
ll=l;
}
else
{
t-=ll;
X-=ll;
ll=l;
}
}
if(X||Y)
printf("\n%d %d",X,Y);
}
if(X==x[i])
{
ll-=abs(Y-y[i]);
Y=y[i];
}
else
{
ll-=abs(X-x[i]);
X=x[i];
}
if(!ll)
{
if(X||Y)
printf("\n%d %d",X,Y);
ll=l;
}
}
return 0;
}
7-2 队列插入
这道题目我写了一个暴力得了15分
15分代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<bits/stdc++.h>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int N=1e4+10;
long long a[N],b[N],dp[N];
char s[N],ans[N];
int tans;
int n;
int cal(int l,int r)
{
memset(dp,0x3f,sizeof(dp));
for(int i=l;i<=r;i++)
*lower_bound(dp+1,dp+n+1,b[i])=b[i];//lower_bound是二分查找函数,当然也可以手写二分
return (lower_bound(dp+1,dp+n+1,0x3f3f3f3f3f3f3f3f)-dp-1);
}
void dfs(int id,int l,int r)
{
if(id==n+1)
{
int t=cal(l,r);
if(t>tans)
{
tans=t;
for(int i=1;i<=n;i++)
ans[i]=s[i];
}
return ;
}
s[id]='L';
b[l-1]=a[id];
dfs(id+1,l-1,r);
s[id]='R';
b[r+1]=a[id];
dfs(id+1,l,r+1);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
s[1]='L';b[1000]=a[1];
dfs(2,1000,1000);
printf("%d\n",tans);
for(int i=1;i<=n;i++)
printf("%c",ans[i]);
return 0;
}
7-4猛犸不上 Ban(最短路)
分析:对于第二种选择显然直接跑一边最短路就可以了,这里就不多说了,下面主要说一下第一种选择。我一开始以为直接跑一个最短路就行,对于第一种说的回到s点,直接枚举与s存在直接边的j,求一个min(d[j]+dis[j][s])即可,但是发现样例都不对,模拟了一下发现存在重边,也就是说从s到j求最短路时经过了直接边s->j,所以就会产生错误,然后就发现思路错了,我就尝试了一下跑多次最短路,也就是对于每一个和s有直接边的j,我都直接跑一边最短路,但是这次最短路不能经过s->j这条边,然后我们再求一下d[j]+dis[j][s],最后取一个最小值即可。交了之后有一个超时,但是看了一下边数和点数,边数是1e5,点数是500,因为我写的是堆优化版的dijkstra,复杂度是O(mlogm),而这道题给的是一个稠密图,所以最好是用朴素版的最短路,直接换成朴素版的就能过了。复杂度是O(n^3)
细节见代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int N=1e6+10;
typedef pair<int,int>PII;
int d[N],n;
int p[503][503];
bool vis[N];
void dijkstra(int x,int u,int v)
{
memset(vis,false,sizeof vis);
memset(d,0x3f,sizeof d);
d[x]=0;
for(int i=1;i<n;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
if(!vis[j]&&(t==-1||d[t]>d[j])) t=j;
vis[t]=true;
for(int j=1;j<=n;j++)
{
if(t==u&&j==v) continue;
if(d[j]>d[t]+p[t][j]) d[j]=d[t]+p[t][j];
}
}
}
int main()
{
int m,s,t;
cin>>n>>m>>s>>t;
memset(p,0x3f,sizeof p);
for(int i=1;i<=m;i++)
{
int u,v,t;
scanf("%d%d%d",&u,&v,&t);
p[u][v]=p[v][u]=t;
}
int t1=0x3f3f3f3f;
for(int i=1;i<=n;i++)
{
if(i==s||p[i][s]==0x3f3f3f3f) continue;
dijkstra(s,s,i);
t1=min(t1,d[i]+p[i][s]);
}
dijkstra(s,0,0);
int t2=d[t];
if(t1==0x3f3f3f3f) printf("-1 ");
else printf("%d ",t1);
if(t2==0x3f3f3f3f) printf("-1\n");
else printf("%d\n",t2);
if(t1!=0x3f3f3f3f&&t1<t2) printf("Win!");
else printf("Lose!");
return 0;
}