最短路

最短路

  $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 }
dijkstra

   这是个很棒的模板,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 }
spfa

  你以为$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 }
Car的旅行路线

 


  华容道:https://www.luogu.org/problemnew/show/P1979

  果真一代神题!

  现在展开一项投票,历年NOIP试题中,到底哪个最难呢?难不仅仅指思维难度,同样包括细节处理的难度,实现的难度等等,总的来说就是哪个题从开始构思到AC所需时间最长呢?

  A.天天爱跑步;

  B.列队;

  C.华容道;

  大家可以在评论里谈一谈看法。

  题意概述:给定一个$n*m$的棋盘,上边有一些格子是固定的,其余格子可以移动,另外还有一个空格子,其他格子想要移动只能往空格处移动。现在给出$T$组询问,每次给出一个棋子的位置和空格的位置,要求把给定格子移动到另一个目标位置去,求最小步数。

  $1n,m30,q500$

  乍一看,这不大水题吗,用$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

posted @ 2018-07-05 14:15  shzr  阅读(206)  评论(0编辑  收藏  举报