最短路
最短路
$Floyd$,$Dijkstra$,$SPFA$...
因为听说$SPFA$会被卡,于是一直用堆优化的$dijkstra$......
希望可以跑得快一点,所以写出了这种东西:
单源最短路:
1 # include <cstdio> 2 # include <iostream> 3 # include <queue> 4 # include <cstring> 5 # define R register int 6 # define mp(a,b) make_pair(a,b) 7 # define inf 2147483647 8 9 using namespace std; 10 11 struct edge 12 { 13 int too,co; 14 int Next; 15 }g[1000005]; 16 17 int h=0,x,f,n,m,s,a,b,cc,Min; 18 char c; 19 int firs[10005]={0}; 20 int dis[10005]={0}; 21 bool vis[10005]={0}; 22 typedef pair <int,int> pii; 23 priority_queue <pii,vector<pii>,greater<pii> > q; 24 25 inline void write(int x) 26 { 27 if(x>9) write(x/10); 28 putchar(x%10+48); 29 } 30 31 inline char gc() 32 { 33 static char buff[1000000],*S=buff,*T=buff; 34 return S==T&&(T=(S=buff)+fread(buff,1,1000000,stdin),S==T)?EOF:*S++; 35 } 36 37 int read() 38 { 39 int x=0; 40 char c=gc(); 41 while (!isdigit(c)) 42 c=gc(); 43 while (isdigit(c)) 44 { 45 x=(x<<3)+(x<<1)+(c^48); 46 c=gc(); 47 } 48 return x; 49 } 50 51 void add(int x,int y,int co) 52 { 53 g[++h].too=y; 54 g[h].co=co; 55 g[h].Next=firs[x]; 56 firs[x]=h; 57 } 58 59 int main() 60 { 61 n=read(); 62 m=read(); 63 s=read(); 64 for (R i=1;i<=m;i++) 65 { 66 a=read(); 67 b=read(); 68 cc=read(); 69 add(a,b,cc); 70 } 71 for (R i=1;i<=n;i++) 72 dis[i]=inf; 73 int beg=s,j; 74 dis[s]=0; 75 q.push(mp(0,s)); 76 while (q.size()) 77 { 78 beg=q.top().second; 79 q.pop(); 80 if(vis[beg]) continue; 81 vis[beg]=true; 82 for (R i=firs[beg];i;i=g[i].Next) 83 { 84 j=g[i].too; 85 if(vis[j]) continue; 86 if(dis[j]<dis[beg]+g[i].co) continue; 87 dis[j]=dis[beg]+g[i].co; 88 q.push(mp(dis[j],j)); 89 } 90 } 91 for (R i=1;i<=n;i++) 92 write(dis[i]),putchar(' '); 93 return 0; 94 }
这是个很棒的模板,wzx教导我说如果删去一点,再改一点就成了spfa,所以也粘在下边吧。
1 // luogu-judger-enable-o2 2 # include <cstdio> 3 # include <iostream> 4 # include <queue> 5 # include <cstring> 6 # define R register int 7 # define inf 2147483647 8 9 using namespace std; 10 11 struct edge 12 { 13 int too,co; 14 int Next; 15 }g[1000005]; 16 17 int h=0,x,f,n,m,s,a,b,cc,Min; 18 char c; 19 int firs[10005]={0}; 20 int dis[10005]={0}; 21 queue <int> q; 22 23 inline void write(int x) 24 { 25 if(x>9) write(x/10); 26 putchar(x%10+48); 27 } 28 29 inline char gc() 30 { 31 static char buff[1000000],*S=buff,*T=buff; 32 return S==T&&(T=(S=buff)+fread(buff,1,1000000,stdin),S==T)?EOF:*S++; 33 } 34 35 int read() 36 { 37 int x=0; 38 char c=gc(); 39 while (!isdigit(c)) 40 c=gc(); 41 while (isdigit(c)) 42 { 43 x=(x<<3)+(x<<1)+(c^48); 44 c=gc(); 45 } 46 return x; 47 } 48 49 void add(int x,int y,int co) 50 { 51 g[++h].too=y; 52 g[h].co=co; 53 g[h].Next=firs[x]; 54 firs[x]=h; 55 } 56 57 int main() 58 { 59 n=read(); 60 m=read(); 61 s=read(); 62 for (R i=1;i<=m;i++) 63 { 64 a=read(); 65 b=read(); 66 cc=read(); 67 add(a,b,cc); 68 } 69 for (R i=1;i<=n;i++) 70 dis[i]=inf; 71 int beg=s,j; 72 dis[s]=0; 73 q.push(s); 74 while (q.size()) 75 { 76 beg=q.front(); 77 q.pop(); 78 for (R i=firs[beg];i;i=g[i].Next) 79 { 80 j=g[i].too; 81 if(dis[beg]+g[i].co>=dis[j]) continue; 82 dis[j]=dis[beg]+g[i].co; 83 q.push(j); 84 } 85 } 86 for (R i=1;i<=n;i++) 87 write(dis[i]),putchar(' '); 88 return 0; 89 }
你以为$Dijkstra$只能求单源最短路吗?不是的,如果把边全部反向还可以求单汇最短路2333
最优贸易:https://www.luogu.org/problemnew/show/P1073
题意概述:求一条从$1$到$n$的路径,使得这条路径上最大点权的点与最小点权的点相差最大。
其实一看题目感觉还是挺简单的。因为上周末wzx说给我讲$Tarjan$时讲到了这道题,在想的时候很奇妙的先想到了两遍最短路的方法,然而刚刚讲完的$Tarjan$被我遗忘了...
首先想到一个方法,记录从$1$到$i$点的路径上最小的点权是谁,把$i$点就当做最大点权来看,统计答案时把整个图都扫一遍就行了。但是这样还有一个问题,就是有的点虽然可以制造比较大的答案,可是走到它那里以后是不能到达终点的,怎么办呢?反着连边,从终点往前跑最短路,如果能跑到某一个点,正着连边时它必然也可以跑到终点。
再把图正着连回来,像最短路一样更新答案(把松弛条件改一下),就完成了。去年夏令营的课件里提到这才是正解,$Tarjan$加拓扑动归是非常痛苦的一种写法,然而两遍最短路也很痛苦...
1 # include <cstdio> 2 # include <iostream> 3 # include <queue> 4 # include <cstring> 5 # define R register int 6 7 using namespace std; 8 9 const int maxn=100009; 10 const int maxm=500009; 11 int h,n,m,x[maxm],y[maxm],z[maxm],tou[maxn],firs[maxn]; 12 int d[maxn],hig[maxn]; 13 int a[maxn]; 14 bool vis[maxn]; 15 typedef pair <int,int> pii; 16 priority_queue <pii,vector<pii>,greater<pii> > q; 17 struct edge 18 { 19 int nex,too; 20 }g[maxn<<1]; 21 22 int read() 23 { 24 int x=0; 25 char c=getchar(); 26 while (!isdigit(c)) 27 c=getchar(); 28 while (isdigit(c)) 29 { 30 x=(x<<3)+(x<<1)+(c^48); 31 c=getchar(); 32 } 33 return x; 34 } 35 36 void dij1(int s) 37 { 38 memset(d,0x7f,sizeof(d)); 39 d[s]=0; 40 q.push(make_pair(d[s],s)); 41 int beg,j; 42 while (q.size()) 43 { 44 beg=q.top().second; 45 q.pop(); 46 if(vis[beg]) continue; 47 vis[beg]=true; 48 for (R i=firs[beg];i;i=g[i].nex) 49 { 50 j=g[i].too; 51 if(vis[j]) continue; 52 if(d[beg]+1>=d[j]) continue; 53 d[j]=d[beg]+1; 54 q.push(make_pair(d[j],j)); 55 } 56 } 57 } 58 59 void dij2(int s) 60 { 61 while (q.size()) q.pop(); 62 memset(d,0x3f,sizeof(d)); 63 memset(vis,0,sizeof(vis)); 64 d[s]=a[s]; 65 q.push(make_pair(d[s],s)); 66 int beg,j; 67 while (q.size()) 68 { 69 beg=q.top().second; 70 q.pop(); 71 if(vis[beg]) continue; 72 vis[beg]=true; 73 for (R i=firs[beg];i;i=g[i].nex) 74 { 75 j=g[i].too; 76 if(vis[j]) continue; 77 if(d[beg]<d[j]||d[beg]<a[j]) 78 { 79 d[j]=min(d[beg],a[j]); 80 q.push(make_pair(d[j],j)); 81 } 82 } 83 } 84 } 85 86 void add(int x,int y) 87 { 88 g[++h].too=y; 89 g[h].nex=firs[x]; 90 firs[x]=h; 91 } 92 93 int main() 94 { 95 scanf("%d%d",&n,&m); 96 for (int i=1;i<=n;++i) 97 a[i]=read(); 98 for (int i=1;i<=m;++i) 99 { 100 x[i]=read(); 101 y[i]=read(); 102 z[i]=read(); 103 if(z[i]==1) add(y[i],x[i]); 104 else add(x[i],y[i]),add(y[i],x[i]); 105 } 106 dij1(n); 107 for (R i=1;i<=n;++i) 108 if(vis[i]) tou[i]=true; 109 h=0; 110 memset(firs,0,sizeof(firs)); 111 for (R i=1;i<=m;++i) 112 { 113 if(z[i]==1) add(x[i],y[i]); 114 else add(x[i],y[i]),add(y[i],x[i]); 115 } 116 dij2(1); 117 int ans=0; 118 for (R i=1;i<=n;++i) 119 if(tou[i]&&vis[i]) ans=max(ans,a[i]-d[i]); 120 printf("%d",ans); 121 return 0; 122 }
bzoj 4152 The Captain:https://www.lydsy.com/JudgeOnline/problem.php?id=4152
Car的旅行路线:https://www.luogu.org/problemnew/show/P1027
这道题难就难在建图,细节比较麻烦,除此以外也没什么特别的;
1 //shzr 2 3 # include <cstdio> 4 # include <iostream> 5 # include <cmath> 6 # include <cstring> 7 # include <queue> 8 9 using namespace std; 10 11 int co,s,t,A,B,firs[500],h=0; 12 struct nod 13 { 14 int x,y; 15 }a[500]; 16 bool vis[500]; 17 double d[500]; 18 typedef pair<double,int> pii; 19 priority_queue <pii,vector<pii>,greater<pii> > q; 20 struct edge 21 { 22 int nex,too; 23 double len; 24 }g[500000]; 25 26 void add(int x,int y,double c) 27 { 28 g[++h].too=y; 29 g[h].nex=firs[x]; 30 firs[x]=h; 31 g[h].len=c; 32 g[++h].too=x; 33 g[h].nex=firs[y]; 34 firs[y]=h; 35 g[h].len=c; 36 } 37 38 void find_four(int i) 39 { 40 nod A=a[4*i+1],B=a[4*i+2],C=a[4*i+3],D; 41 long long la,lb,lc; 42 la=(B.x-C.x)*(B.x-C.x)+(B.y-C.y)*(B.y-C.y); 43 lb=(A.x-C.x)*(A.x-C.x)+(A.y-C.y)*(A.y-C.y); 44 lc=(A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y); 45 if(la+lb==lc) 46 { 47 D.x=B.x-C.x+A.x; 48 D.y=B.y-C.y+A.y; 49 } 50 if(la+lc==lb) 51 { 52 D.x=-B.x+C.x+A.x; 53 D.y=-B.y+C.y+A.y; 54 } 55 if(lb+lc==la) 56 { 57 D.x=B.x+C.x-A.x; 58 D.y=B.y+C.y-A.y; 59 } 60 a[4*i+4]=D; 61 } 62 63 void dij(int s) 64 { 65 memset(d,127,sizeof(d)); 66 memset(vis,0,sizeof(vis)); 67 d[s]=0; 68 while (q.size()) q.pop(); 69 q.push(make_pair(d[s],s)); 70 int j,beg; 71 while (q.size()) 72 { 73 beg=q.top().second; 74 q.pop(); 75 if(vis[beg]) continue; 76 vis[beg]=true; 77 for (int i=firs[beg];i;i=g[i].nex) 78 { 79 j=g[i].too; 80 if(d[beg]+g[i].len>=d[j]) continue; 81 d[j]=d[beg]+g[i].len; 82 q.push(make_pair(d[j],j)); 83 } 84 } 85 } 86 87 int main() 88 { 89 int T; 90 scanf("%d",&T); 91 while (T--) 92 { 93 scanf("%d%d%d%d",&s,&t,&A,&B); 94 h=0; 95 for (int i=0;i<s;++i) 96 { 97 scanf("%d%d%d%d%d%d",&a[4*i+1].x,&a[4*i+1].y,&a[4*i+2].x,&a[4*i+2].y,&a[4*i+3].x,&a[4*i+3].y); 98 scanf("%d",&co); 99 find_four(i); 100 for (int m=1;m<=4;++m) 101 for (int n=m+1;n<=4;++n) 102 add(4*i+m,4*i+n,co*sqrt((a[4*i+m].x-a[4*i+n].x)*(a[4*i+m].x-a[4*i+n].x)+(a[4*i+m].y-a[4*i+n].y)*(a[4*i+m].y-a[4*i+n].y))); 103 for (int j=1;j<=4;++j) 104 for (int k=1;k<=4*i;++k) 105 add(4*i+j,k,sqrt((a[4*i+j].x-a[k].x)*(a[4*i+j].x-a[k].x)+(a[4*i+j].y-a[k].y)*(a[4*i+j].y-a[k].y))*t); 106 } 107 for (int i=1;i<=4;++i) 108 { 109 add(0,(A-1)*4+i,0); 110 add(s*4+5,(B-1)*4+i,0); 111 } 112 dij(0); 113 printf("%.1lf\n",d[s*4+5]); 114 } 115 return 0; 116 }
华容道:https://www.luogu.org/problemnew/show/P1979
果真一代神题!
现在展开一项投票,历年NOIP试题中,到底哪个最难呢?难不仅仅指思维难度,同样包括细节处理的难度,实现的难度等等,总的来说就是哪个题从开始构思到AC所需时间最长呢?
A.天天爱跑步;
B.列队;
C.华容道;
大家可以在评论里谈一谈看法。
题意概述:给定一个$n*m$的棋盘,上边有一些格子是固定的,其余格子可以移动,另外还有一个空格子,其他格子想要移动只能往空格处移动。现在给出$T$组询问,每次给出一个棋子的位置和空格的位置,要求把给定格子移动到另一个目标位置去,求最小步数。
$1≤n,m≤30,q≤500$
乍一看,这不大水题吗,用$a[i][j][k][z]$表示给定格子在$(i,j)$,空格子在$(k,z)$的状态,给每一个状态附一个$id$,五重循环连边,bfs不就好了?然后:
我是一个有原则的人!NOIP的真题绝对不开O2,但是竟然失误的使用了STL的队列....改成手写队列再交一次:
重新计算一番复杂度,发现....确实是我$Naive$了.
于是就跑去看题解~NOIP 2013 能AK的都是神仙
其实有很多状态都是可以预处理的,虽然预处理要花一点时间,但是因为询问组数比较大,还是非常有优势的。
显然,指定格子要移动,必然是往空格处移动,而且它所走的每一步路必然都是空格提早一步到那里为他铺好的,所以现在对于每个格子我们保存四种状态,分别是空格在它的上下左右的情况,并对每一种情况赋一个$id$.考虑一下,指定格子走的轨迹是什么样的:首先空格子(排除万难来到他身边),他和空格交换位置,空格走到他打算走的下一步的位置等待,他再和空格交换……在这个状态里面,空格第一次到他身边的步数,空格走到他的另一侧的步数不会是完全一样的,所以放弃$bfs$,还是连边跑最短路.
开始连边啦。和空格交换的步数当然是$1$,先轻松愉快地把这些边连起来,巧妙的安排四个方向的代号,就可以异或$1$来表示每个方向正对面的方向.空格子到指定格子的步数在知道指定格子的编号之前是不可能确定的,先不管他.空格绕着指定格子转的边权也可以$bfs$来求,这里注意移动过程中一定不能让空格和指定格子再交换,否则就把棋盘弄乱了.每次读入一个询问,再将空格到指定格子四向的边权$bfs$四次求出来,连上边.这时我们可以采用某虽然死了但是活在人民心中的算法把答案求出来.不过还是堆优化$dij$比较稳啦.
1 // luogu-judger-enable-o2 2 # include <cstdio> 3 # include <iostream> 4 # include <cstring> 5 # include <queue> 6 # define inf 100000009 7 # define R register int 8 9 using namespace std; 10 11 const int maxn=32; 12 const int dx[]={-1,1,0,0}; 13 const int dy[]={0,0,1,-1}; 14 int h,n,m,Q,id[maxn][maxn][4],cnt,a[maxn][maxn],ex,ey,sx,sy,tx,ty; 15 int firs[maxn*maxn*5],mov[maxn][maxn][4][4]; 16 int d[maxn*maxn*5],in_que[maxn*maxn*5]; 17 int b[maxn*maxn*5]; 18 queue <int> sq; 19 struct edge 20 { 21 int too,nex,co; 22 }g[20005]; 23 struct nod 24 { 25 int x,y; 26 }q[maxn*maxn*5]; 27 28 bool mw (int x,int y) 29 { 30 if(a[x][y]==0) return false; 31 if(x<1||x>n||y<1||y>m) return false; 32 return true; 33 } 34 35 inline int read() 36 { 37 int x=0; 38 char c=getchar(); 39 while (!isdigit(c)) c=getchar(); 40 while (isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar(); 41 return x; 42 } 43 44 inline void add (int x,int y,int co) 45 { 46 g[++h].too=y; 47 g[h].nex=firs[x]; 48 g[h].co=co; 49 firs[x]=h; 50 } 51 52 int rotate (int x,int y,int d1,int d2) 53 { 54 int xx,yy,h=1,t=0,ans=-1; 55 q[++t].x=x+dx[d1]; 56 q[t].y=y+dy[d1]; 57 b[t]=0; 58 a[x][y]=0; 59 while (h<=t) 60 { 61 xx=q[h].x; 62 yy=q[h].y; 63 if(xx==x+dx[d2]&&yy==y+dy[d2]) 64 { 65 ans=b[h]; 66 break; 67 } 68 for (R d=0;d<4;++d) 69 { 70 if(mw(xx+dx[d],yy+dy[d])) 71 { 72 q[++t].x=xx+dx[d]; 73 q[t].y=yy+dy[d]; 74 b[t]=b[h]+1; 75 a[ xx+dx[d] ][ yy+dy[d] ]=0; 76 } 77 } 78 h++; 79 } 80 a[x][y]=1; 81 for (R i=1;i<=t;++i) 82 a[ q[i].x ][ q[i].y ]=1; 83 if(ans!=-1) return ans; 84 return inf; 85 } 86 87 void pre (int x,int y) 88 { 89 int dis; 90 for (R d=0;d<4;++d) 91 { 92 if(!mw(x+dx[d],y+dy[d])) continue; 93 for (R dd=0;dd<4;++dd) 94 { 95 if(!mw(x+dx[dd],y+dy[dd])) continue; 96 dis=mov[x][y][d][dd]=mov[x][y][dd][d]=rotate(x,y,d,dd); 97 if(dis!=inf) 98 { 99 add(id[x][y][d],id[x][y][dd],dis); 100 add(id[x][y][dd],id[x][y][d],dis); 101 } 102 } 103 } 104 } 105 106 int dis (int sx,int sy,int ex,int ey,int tx,int ty) //把ex,ey处的空格子移到tx,ty,中间不能经过sx,sy 107 { 108 int xx,yy,h=1,t=0,ans=-1; 109 a[ex][ey]=a[sx][sy]=0; 110 q[++t].x=ex; 111 q[t].y=ey; 112 b[t]=0; 113 while (h<=t) 114 { 115 xx=q[h].x; 116 yy=q[h].y; 117 if(xx==tx&&yy==ty) 118 { 119 ans=b[h]; 120 break; 121 } 122 for (R d=0;d<4;++d) 123 { 124 if(mw(xx+dx[d],yy+dy[d])) 125 { 126 q[++t].x=xx+dx[d]; 127 q[t].y=yy+dy[d]; 128 b[t]=b[h]+1; 129 a[ xx+dx[d] ][ yy+dy[d] ]=0; 130 } 131 } 132 h++; 133 } 134 a[ex][ey]=a[sx][sy]=1; 135 for (R i=1;i<=t;++i) 136 a[ q[i].x ][ q[i].y ]=1; 137 if(ans!=-1) return ans; 138 return inf; 139 } 140 141 void spfa (int beg) 142 { 143 memset(d,127,sizeof(d)); 144 memset(in_que,0,sizeof(in_que)); 145 while (sq.size()) sq.pop(); 146 d[beg]=0; 147 in_que[beg]=true; 148 int j,k; 149 sq.push(beg); 150 while (sq.size()) 151 { 152 k=sq.front(); 153 sq.pop(); 154 in_que[k]=false; 155 for (R i=firs[k];i;i=g[i].nex) 156 { 157 j=g[i].too; 158 if(d[k]+g[i].co>=d[j]) continue; 159 d[j]=d[k]+g[i].co; 160 if(!in_que[j]) sq.push(j),in_que[j]=true; 161 } 162 } 163 } 164 165 int main() 166 { 167 scanf("%d%d%d",&n,&m,&Q); 168 169 for (R i=1;i<=n;++i) 170 for (R j=1;j<=m;++j) 171 scanf("%d",&a[i][j]); 172 173 for (R i=1;i<=n;++i) 174 for (R j=1;j<=m;++j) 175 { 176 if(a[i][j]==0) continue; 177 for (R k=0;k<4;++k) 178 if(mw(i+dx[k],j+dy[k])) id[i][j][k]=++cnt; 179 } 180 181 for (R i=1;i<=n;++i) 182 for (R j=1;j<=m;++j) 183 { 184 if(!a[i][j]) continue; 185 for (R k=0;k<4;++k) 186 { 187 if(mw(i+dx[k],j+dy[k])) 188 add(id[i][j][k],id[ i+dx[k] ][ j+dy[k] ][k^1],1); 189 } 190 } 191 192 for (R i=1;i<=n;++i) 193 for (R j=1;j<=m;++j) 194 if(a[i][j]==1) pre(i,j); 195 196 cnt++; 197 int th=h; 198 for (R i=1;i<=Q;++i) 199 { 200 ex=read(),ey=read(),sx=read(),sy=read(),tx=read(),ty=read(); 201 if(sx==tx&&sy==ty) { printf("0\n"); continue; } 202 h=th; 203 firs[cnt]=0; 204 for (R k=0;k<4;++k) 205 if(mw(sx+dx[k],sy+dy[k])) 206 { 207 int t=dis(sx,sy,ex,ey,sx+dx[k],sy+dy[k]); 208 add(cnt,id[sx][sy][k],t); 209 } 210 spfa(cnt); 211 int ans=inf; 212 for (R k=0;k<4;++k) 213 ans=min(ans,d[ id[tx][ty][k] ]); 214 if(ans==inf) printf("-1\n"); 215 else printf("%d\n",ans); 216 } 217 return 0; 218 }
---shzr