电路维修 这道题虽然乍一看就会想斜对角的两点之间边权受初始电路的影响要么为0要么为1,但是有一个思考点就是可以通过奇偶性,证明相邻的两个点是不可能在同一个电路中。练习一下双端队列。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; const int dx[4]={-1,-1,1,1}; const int dy[4]={-1,1,-1,1}; char ss[510][510]; int xx[3100000],yy[3100000],cc[510][510]; int main() { int T; scanf("%d",&T); while(T--) { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%s",ss[i]+1); memset(cc,-1,sizeof(cc)); xx[n*m+1]=1,yy[n*m+1]=1;cc[1][1]=0; int head=n*m+1,tail=n*m+1;bool bk=false; while(head<=tail) { int x=xx[head],y=yy[head];head++; if(x==n+1&&y==m+1){printf("%d ",cc[x][y]);bk=true;break;} for(int k=0;k<=3;k++) { int tx=x+dx[k],ty=y+dy[k]; if(0<tx&&tx<=n+1&&0<ty&&ty<=m+1&&(cc[tx][ty]==-1||cc[tx][ty]>cc[x][y])) { int g=(!((x>tx)^(y>ty)))?((!(ss[min(x,tx)][min(y,ty)]=='/'))?0:1):((ss[min(x,tx)][min(y,ty)]=='/')?0:1); if(g==0) { head--; xx[head]=tx,yy[head]=ty,cc[tx][ty]=cc[x][y]; } else { tail++; xx[tail]=tx,yy[tail]=ty,cc[tx][ty]=cc[x][y]+1; } } } } if(bk==false)printf("NO SOLUTION "); } return 0; }
poj3635 有点尴尬啊我写的堆优化bfs卡不过去。。。去A*那再做吧
upd:这算哪门子A*啊,真是被discuss的水逼坑死。。。我写了个用路径中最小价格的加油站*油数做预估函数的A*跑的比堆+bfs还慢,结果就是正解就是判断是否之前已经走过更短的(对没错就像最短路那样),剪枝一下就过了???(思维僵化啊菜鸡yzh)
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<queue> using namespace std; int n,m,c[1100]; struct edge { int x,y,d,next; }a[21000];int len,last[1100]; void ins(int x,int y,int d) { len++; a[len].x=x;a[len].y=y;a[len].d=d; a[len].next=last[x];last[x]=len; } int C,st,ed; struct Astar { int x,l,s; friend bool operator>(Astar n1,Astar n2){return n1.s>n2.s;} };priority_queue<Astar,vector<Astar>,greater<Astar> >q; int g[1100][110]; void bfs() { memset(g,63,sizeof(g));g[st][0]=0; while(!q.empty())q.pop(); Astar t; t.x=st, t.l=0, t.s=0, q.push(t); while(!q.empty()) { Astar tno=q.top();q.pop(); if(tno.x==ed) { printf("%d ",tno.s); return ; } if(tno.l+1<=C&&g[tno.x][tno.l+1]>g[tno.x][tno.l]+c[tno.x]) { g[tno.x][tno.l+1]=g[tno.x][tno.l]+c[tno.x]; t.x=tno.x, t.l=tno.l+1, t.s=tno.s+c[t.x], q.push(t); } for(int k=last[tno.x];k;k=a[k].next) { int y=a[k].y; if(tno.l>=a[k].d&&g[y][tno.l-a[k].d]>g[tno.x][tno.l]) { g[y][tno.l-a[k].d]=g[tno.x][tno.l]; t.x=y, t.l=tno.l-a[k].d, t.s=tno.s, q.push(t); } } } printf("impossible "); } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&c[i]); for(int i=1;i<=m;i++) { int x,y,d; scanf("%d%d%d",&x,&y,&d);x++,y++; ins(x,y,d);ins(y,x,d); } int Q; scanf("%d",&Q); while(Q--) { scanf("%d%d%d",&C,&st,&ed);st++,ed++; bfs(); } return 0; }
hdoj3085 这题真是折腾死了。。。题意有点不清(去找discuss)做法是两个轮流走并且枚举时间层数判断,因为有可能某人(几乎是明明)对于当前时间能够到达的点比另一个多得多。恶心的是这个明明同学一秒三步非常难判,一开始我是写了个三步的方向,结果发现这样会穿墙,然后改成三个走一步套在一起,结果发现拓展的时候,当前秒走了1步和2/3步的拓展是有差异的,但是秒数一样就体现不出来,最后解决的方法就是以1/3秒为单位走,圆满解决
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; const int dx[16]={0,-1,0,1}; const int dy[16]={-1,0,1,0}; int n,m,gx1,gy1,gx2,gy2; char ss[810][810]; struct node { int x,y,c; }list[2][1100000]; int d[2][810][810]; bool check(int x,int y,int asd){return 0<x&&x<=n&&0<y&&y<=m&&d[asd][x][y]==-1&&ss[x][y]!='X';} int getdis(int x,int y){return min(abs(gx1-x)+abs(gy1-y),abs(gx2-x)+abs(gy2-y));} int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); int T; scanf("%d",&T); while(T--) { int gx,gy,bx,by,x,y;gx1=-1; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%s",ss[i]+1); for(int j=1;j<=m;j++) if(ss[i][j]=='M')bx=i,by=j; else if(ss[i][j]=='G')gx=i,gy=j; else if(ss[i][j]=='Z') { if(gx1==-1)gx1=i,gy1=j; else gx2=i,gy2=j; } } int head[2],tail[2],dep=0; bool bk=false; head[0]=1, tail[0]=2, list[0][1].x=bx, list[0][1].y=by; head[1]=1, tail[1]=2, list[1][1].x=gx, list[1][1].y=gy; memset(d,-1,sizeof(d)); d[0][bx][by]=0, d[1][gx][gy]=0; if(getdis(bx,by)<=2||getdis(gx,gy)<=2){printf("-1 ");continue;} while(head[0]<tail[0]&&head[1]<tail[1]) { while(d[0][list[0][head[0]].x][list[0][head[0]].y]==dep) { x=list[0][head[0]].x,y=list[0][head[0]].y; if(d[0][x][y]!=-1&&d[1][x][y]!=-1) { printf("%d ",max(d[0][x][y]%3==0?d[0][x][y]/3:d[0][x][y]/3+1,d[1][x][y]/3)); bk=true;break; } if(getdis(x,y)>2*(d[0][x][y]/3+1)) { for(int k=0;k<=3;k++) { int tx=x+dx[k],ty=y+dy[k]; if(check(tx,ty,0)&&getdis(tx,ty)>2*(d[0][x][y]/3+1)) { d[0][tx][ty]=d[0][x][y]+1; list[0][tail[0]].x=tx, list[0][tail[0]].y=ty; tail[0]++; } } } head[0]++; } if(bk==true)break; while(d[1][list[1][head[1]].x][list[1][head[1]].y]==dep) { x=list[1][head[1]].x,y=list[1][head[1]].y; if(d[0][x][y]!=-1&&d[1][x][y]!=-1) { printf("%d ",max(d[0][x][y]%3==0?d[0][x][y]/3:d[0][x][y]/3+1,d[1][x][y]/3)); bk=true;break; } if(getdis(x,y)>2*(d[1][x][y]/3+1)) { for(int k=0;k<=3;k++) { int tx=x+dx[k],ty=y+dy[k],dis=getdis(tx,ty); if(check(tx,ty,1)&&dis>2*((d[1][x][y]+3)/3)) { d[1][tx][ty]=d[1][x][y]+3; list[1][tail[1]].x=tx, list[1][tail[1]].y=ty; tail[1]++; } } } head[1]++; } if(bk==true)break; dep++; } /* for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) printf("%d ",d[0][i][j]==-1?9:d[0][i][j]); printf(" "); } printf(" "); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) printf("%d ",d[1][i][j]==-1?9:d[1][i][j]); printf(" "); }*/ if(bk==false)printf("-1 "); } return 0; }
宽搜还是比深搜玩的好一些,但是比较复杂的题细节处理的不好