传送门:洛谷 P4667 Switch the Lamp On
重题(弱化版):洛谷 P2243 电路维修
题目描述:
每条电线可旋转 (90^circ)指向另一方向,则求从左上角到右下角最少要旋转的次数
算法分析:
前言:为了测试算法速度,本题没有谜の卡常
(BFS ?) 貌似对我这样的蒟蒻不太友好。该题本质上是沿对角线有一条路径,只不过其中顺着原电线方向的权值为(0),反之为(1),这样跑一遍(Dijkstra)即可。(自从过于不友好的 P4779 单源最短路径(标准版)后就转用(Dijkstra))果断套堆优化模板——
突然发现:N*M=250000 ???
那前面的(WA)呢?经过深思熟虑,突然发现:对角线的连线是(N*M),这就意味着图是以点的形式呈现时,应是((N+1)times(M+1)),果断套堆优化模板(第一次用(class)还有点小激动)——
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #define in(x) x=read(); using namespace std; const int maxN=1000001,maxM=1000001,maxQ=500; class algorithm { public: int dis[maxN+1]; void addedge(int x,int y,int value) { tot++; edge[tot].from=x;edge[tot].to=y; edge[tot].value=value; edge[tot].next=head[x]; head[x]=tot; } void addtwo(int x,int y,int value) { addedge(x,y,value); addedge(y,x,value); } void clear() { memset(dis,0x3f,sizeof(dis)); memset(vis,false,sizeof(vis)); memset(head,0,sizeof(head)); tot=0; } void dijkstra(int s) { dis[s]=0; q.push(make_pair(0,s)); while(q.size()) { int x=q.top().second; q.pop(); if(vis[x]) continue; vis[x]=true; for(int i=head[x];i;i=edge[i].next) { if(dis[edge[i].to]>dis[x]+edge[i].value) { dis[edge[i].to]=dis[x]+edge[i].value; q.push(make_pair(-dis[edge[i].to],edge[i].to)); } } } } private: struct Node { int value,from,to,next; }edge[maxM+1]; int head[maxN+1],tot; bool vis[maxN+1]; priority_queue<pair<int,int> > q; }; int n,m,x,y,z; char map[maxQ+1][maxQ+1]; algorithm task; void subtask(); inline int read(); int main() { subtask(); return 0; } void subtask() { task.clear(); in(n); in(m); n++; m++; for(int i=1;i<n;i++) scanf("%s",map[i]+1); for(int i=1;i<n;i++) for(int j=1;j<m;j++) if(map[i][j]==92) { task.addtwo(i*m-m+j,i*m+j+1,0); task.addtwo(i*m-m+j+1,i*m+j,1); } else { task.addtwo(i*m-m+j,i*m+j+1,1); task.addtwo(i*m-m+j+1,i*m+j,0); } task.dijkstra(1); if(task.dis[n*m]==0x3f3f3f3f) printf("NO SOLUTIONn"); else printf("%dn",task.dis[n*m]); } inline int read() { char ch=getchar(); int num=0,f=1; while((ch<'0' || ch>'9') && ch!='-') ch=getchar(); if(ch=='-') {f=-1; ch=getchar();} while(ch>='0' && ch<='9') { num=num*10+ch-'0'; ch=getchar(); } return num*f; }
——然而并不是(AC)。那几个TLE是什么意思!
经过认真观察,突然发现:
时空限制 150ms / 128MB
显然,用(priority queue)是不够快的(然而吸氧过了),那当然是要用线段树优化了(堆:???),然后就去了解了一下线段树优化 (Dijkstra)
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #define ls k<<1 #define rs k<<1|1 #define mid ((l+r)>>1) #define in(x) x=read(); using namespace std; const int maxN=500001,maxM=1000001; const int inf=0x3f3f3f3f,maxQ=500; class algorithm { public: int dis[maxN+1]; void addedge(int x,int y,int value) { tot++; edge[tot].from=x;edge[tot].to=y; edge[tot].value=value; edge[tot].next=head[x]; head[x]=tot; } void addtwo(int x,int y,int value) { addedge(x,y,value); addedge(y,x,value); } void clear() { memset(dis,0x3f,sizeof(dis)); memset(vis,false,sizeof(vis)); memset(head,0,sizeof(head)); memset(sum,0x3f,sizeof(sum)); tot=0; } void update(int k,int l,int r,int u,int w) { if(l==r) {sum[k]=w; return;} if(u<=mid) update(ls,l,mid,u,w); else update(rs,mid+1,r,u,w); pushup(k); } int query(int k,int l,int r) { if(l==r) return l; if(sum[ls]<sum[rs]) return query(ls,l,mid); else return query(rs,mid+1,r); } void dijkstra(int s,int n) { dis[s]=0; update(1,1,n,s,0); while(sum[1]^inf) { int x=query(1,1,n); update(1,1,n,x,inf); for(int i=head[x];i;i=edge[i].next) if(dis[edge[i].to]>dis[x]+edge[i].value) { dis[edge[i].to]=dis[x]+edge[i].value; update(1,1,n,edge[i].to,dis[edge[i].to]); } } } private: struct Node { int value,from,to,next; }edge[maxM+1]; int head[maxN+1],tot,sum[4*maxN+1]; bool vis[maxN+1]; void pushup(int k) {sum[k]=min(sum[ls],sum[rs]);} }; int n,m,x,y,z; char map[maxQ+1][maxQ+1]; algorithm task; void subtask(); inline int read(); int main() { subtask(); return 0; } void subtask() { task.clear(); in(n); in(m); n++; m++; for(int i=1;i<n;i++) scanf("%s",map[i]+1); for(int i=1;i<n;i++) for(int j=1;j<m;j++) if(map[i][j]==92) { task.addtwo(i*m-m+j,i*m+j+1,0); task.addtwo(i*m-m+j+1,i*m+j,1); } else { task.addtwo(i*m-m+j,i*m+j+1,1); task.addtwo(i*m-m+j+1,i*m+j,0); } task.dijkstra(1,n*m); if(task.dis[n*m]==0x3f3f3f3f) printf("NO SOLUTIONn"); else printf("%dn",task.dis[n*m]); } inline int read() { char ch=getchar(); int num=0,f=1; while((ch<'0' || ch>'9') && ch!='-') ch=getchar(); if(ch=='-') {f=-1; ch=getchar();} while(ch>='0' && ch<='9') { num=num*10+ch-'0'; ch=getchar(); } return num*f; }
令人欣慰的绿色:
然而并没有(逃)
普通线段树同学不够优秀(然而吸氧又过了),那当然是要用zkw线段树优化了(线段树:???),然后就又去借(chao)鉴(lai)了一下zkw线段树优化 (Dijkstra)
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define ls x<<1 #define rs x<<1|1 #define in(x) x=read(); using namespace std; const int maxN=500001,maxM=1000001; const int inf=0x7fffffff,maxQ=500; class algorithm { public: int dis[maxN+1],ans[maxN+1]; inline void build(int size) { for(leaf=1;leaf<=size;leaf<<=1); leaf--; for(int i=1;i<=size;++i) tree[leaf+i]=i; } void update(int x,int y) { dis[x]=y; x+=leaf; x>>=1; while(x) { tree[x]=(dis[tree[ls]]<dis[tree[rs]])?tree[ls]:tree[rs]; x>>=1; } } inline void addedge(int x,int y,int value) { edge[++tot].from=x;edge[tot].to=y; edge[tot].value=value; edge[tot].next=head[x]; head[x]=tot; } inline void addtwo(int x,int y,int value) { addedge(x,y,value); addedge(y,x,value); } inline void clear() { memset(dis,0x3f,sizeof(dis)); memset(tree,0,sizeof(tree)); memset(ans,0x3f,sizeof(ans)); tot=0; } void dijkstra(int s,int size) { build(size); dis[s]=0;int x=s,dist; for(int i=1;i<=size;++i) { dist=ans[x]=dis[x]; update(x,inf); for(int i=head[x];i;i=edge[i].next) if(dis[edge[i].to]<inf && dis[edge[i].to]>dist+edge[i].value) update(edge[i].to,dist+edge[i].value); x=tree[1]; } } private: struct Node { int value,from,to,next; }edge[maxM+1]; int head[maxN+1],tot,tree[maxN<<2],leaf; }; int n,m,x,y,z; char map[maxQ+1][maxQ+1]; algorithm task; void subtask(); inline int read(); int main() { subtask(); return 0; } void subtask() { task.clear(); in(n); in(m); n++; m++; for(int i=1;i<n;i++) scanf("%s",map[i]+1); for(int i=1;i<n;i++) for(int j=1;j<m;j++) if(map[i][j]==92) { task.addtwo(i*m-m+j,i*m+j+1,0); task.addtwo(i*m-m+j+1,i*m+j,1); } else { task.addtwo(i*m-m+j,i*m+j+1,1); task.addtwo(i*m-m+j+1,i*m+j,0); } task.dijkstra(1,n*m); if(task.ans[n*m]!=0x3f3f3f3f) printf("%d",task.ans[n*m]); else printf("NO SOLUTION"); } inline int read() { char ch=getchar(); int num=0,f=1; while((ch<'0' || ch>'9') && ch!='-') ch=getchar(); if(ch=='-') {f=-1; ch=getchar();} while(ch>='0' && ch<='9') { num=num*10+ch-'0'; ch=getchar(); } return num*f; }
真 · 令人欣慰的绿色(无吸氧):
(后来看题解发现貌似手写堆也能过QWQ (太懒而不想写),卡常技术还有待提高啊)
相关知识
洛谷 P1077 摆花 题解
植物生长灯(Plant growth lamp).doc
LAMP:检疫植物病原体的早期预警工具
Java中的switch分支注意点
犊牛腹泻病原体沙门氏菌与BVD病毒LAMP检测体系的优化与初步应用
蓝莓枝枯病的重要病原真菌鉴定及LAMP快速检测技术研究
园艺模拟游戏《花园生活》将于2024年登陆Switch平台
咏洛赋
保加利亚卡尔洛沃市庆祝玫瑰节
森环森保所研究成功—“一种LAMP快速检测核型多角体病毒的方法”获国家发明专利授权
网址: 洛谷 P4667 Switch the Lamp On https://m.huajiangbk.com/newsview990185.html
上一篇: 洛谷 P1005 矩阵取数游戏 |
下一篇: 香菜种植:全面指南、时间要求和方 |