冲刺2018模拟赛3-赛后总结

1|0T1 冰岛

1|1看到这道题目就想到了bfs,开始理解错了题意认为滑雪随时都可以停下于是就有了下面的代码(而且还一度把dfs和bfs记录步数的方法搞混了)

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; int ok=0; int n; int mp[2000][2000]; int x1,y1,x2,y2; int dx[]={1,-1,0,0}; int dy[]={0,0,-1,1}; struct node{ int x,y,last_x,last_y,ans; }; int vis[2000][2000]; inline void bfs(int x,int y){ queue<node> Q; //ans++; vis[x][y]=1; Q.push({x,y,-1,-1,0}); while(!Q.empty()){ //printf("%d\n",ans); node fr=Q.front();Q.pop(); // printf("x=%d y=%d ans=%d\n",fr.x,fr.y,ans); for(int i=0;i<4;i++){ node l; l.x=dx[i]+fr.x; l.y=dy[i]+fr.y; int sx=l.x,sy=l.y; if(sx>n||sx<1||sy>n||sy<1||vis[sx][sy]||mp[sx][sy])continue; vis[sx][sy]=1; if((dx[i]!=fr.last_x||dy[i]!=fr.last_y)){ l.ans=fr.ans+1; } //printf("x=%d y=%d last_x=%d last_y=%d ans=%d\n",sx,sy,fr.last_x,fr.last_y,l.ans); if(x2==sx&&y2==sy){ printf("%d",l.ans); ok=1; return ; } Q.push({sx,sy,dx[i],dy[i],l.ans}); //return ; } } } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ cin>>mp[i][j]; } } scanf("%d %d",&x1,&y1); scanf("%d %d",&x2,&y2); bfs(x1,y1); if(!ok){ printf("impossible"); } return 0; }

1|2幸好后面发现了是要撞墙了才能停下,于是就AC了;

1|3总结:

1|41、bfs中这一步的步数因等于上一步的步数+1,所以记录步数的方法应该使用开一个数组用坐标来存当位置位于这个坐标时的步数或者像我一样用STL和struct

1|52、一定要认真审题!!!

1|63、打代码时速度不要过快,不然后面DEBUG会累死

2|0T2保送

2|1完全不懂,之后应了解相关概率的知识

3|0T3A-B

3|1将A-B=C转化为A-C=B来枚举即可

4|0T4[遇见]

4|1这道题目直接打了部分分,正解其实很好理解,因为隐藏的道路不要时间所以直接把隐藏的道路梭为节点即可

5|0标程

#include<cstdio> #include<iostream> #include<cstring> #include<queue> #include<algorithm> #define maxn 300010 using namespace std; int n,m1,m2,cnt,hl[maxn],dis[maxn],vis[maxn],cost[maxn],coin[maxn],fa[maxn]; queue<int>Q; struct Edge{ int u,v,w,t,ne; }e[maxn]; void add(int u,int v,int w,int t) { e[++cnt].u=u; e[cnt].v=v; e[cnt].w=w; e[cnt].t=t; e[cnt].ne=hl[u]; hl[u]=cnt; } int find(int x) { return x==fa[x]?x:fa[x]=find(fa[x]); } void spfa(int x) { memset(dis,127/3,sizeof(dis)); Q.push(x); dis[x]=0; cost[x]=coin[x]; vis[x]=1; while(!Q.empty()){ int u=Q.front(); Q.pop(); vis[u]=0; for(int i=hl[u];i;i=e[i].ne){ int v=e[i].v,w=e[i].w,t=e[i].t; if(dis[v]>dis[u]+t||(dis[v]==dis[u]+t&&cost[v]<cost[u]+w+coin[v])){ dis[v]=dis[u]+t; cost[v]=cost[u]+w+coin[v]; if(!vis[v]){ vis[v]=1; Q.push(v); } } } } } int main() { //freopen("meet.in","r",stdin); //freopen("meet.out","w",stdout); int x,y,w,t; scanf("%d%d%d",&n,&m1,&m2); for(int i=1;i<=n;++i) fa[i]=i; for(int i=1;i<=m2;++i){ scanf("%d%d%d",&x,&y,&w); int k1=find(x),k2=find(y); if(k1!=k2){ fa[k1]=k2; coin[k2]+=coin[k1]+w; } else coin[k1]+=w; } for(int i=1;i<=m1;++i){ scanf("%d%d%d%d",&x,&y,&w,&t); if(find(x)!=find(y)) add(find(x),find(y),w,t); } spfa(find(1)); printf("%d %d\n",dis[find(n)],cost[find(n)]); return 0; }

5|1解析:

1|0tag:最短路 并查集 缩点

思路:先跑裸最短路,再考虑双向边(隐藏通道)怎么处理。既然时间花费为0,而且要最快通过,那么可以忽略两点连接的其他边,然后通道连接的两点可以缩为一点,将金币加到祖先点。这时需要灵活使用并查集,之后的每次调用都是看祖先点。


__EOF__

本文作者Kdlyh
本文链接https://www.cnblogs.com/kdlyh/p/17777008.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   加固文明幻景  阅读(6)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示