bfs可以O(V+E)求解边权全为1的图上最短路。
而当边权只有0或1时,使用其它最短路算法是有些浪费的,此时可以使用bfs的变种:0-1 bfs来快速求解,复杂度仍为O(V+E).
D. Labyrinth(CF 1064D)
给你一个n*m的迷宫,给出起始点,向左不超过L,向右不超过R。
求最多能走到的点的个数。
当我们单纯的dfs(int x,int y,int L,int R) //起点,L,R的时候,肯定会tle 的
我们可知,从起始点开始,向上向下的消耗的价值,也就是边权都为0,而向左向右的边权都为1.
这时,只有0和1的图就可以用 01bfs来写。
用一个双端队列。deque<node>que。(node结点来储存信息和限制条件)
当边权为0时,就把这个点加入顶端。当边权为1时,把点加入尾端。
que.push_front(); que.pop_front();
que.push_back();
这道题就从起始点开始遍历,上下两个点加入顶端,左右两个点加入尾端。
求最多能遍历到的点的个数就可以了。
因为每个点最多只可能遍历一次,因此可以省去bok数组。
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 #include <set> 6 #include <queue> 7 #include <stack> 8 #include <string> 9 #include <cstring> 10 #include <vector> 11 #include <map> 12 #include<ctime> 13 //#include <unordered_map> 14 #define mem( a ,x ) memset( a , x ,sizeof(a) ) 15 #define rep( i ,x ,y ) for( int i = x ; i<=y ;i++ ) 16 #define lson l ,mid ,pos<<1 17 #define rson mid+1 ,r ,pos<<1|1 18 using namespace std; 19 typedef long long ll ; 20 typedef pair<int ,int> pii; 21 typedef pair<ll ,int> pli; 22 const int inf = 0x3f3f3f3f; 23 const ll mod=998244353; 24 const int N=100000+50; 25 int n,m,r,c,L,R; 26 char s[2010][2010]; 27 int bok[2010][2010]; 28 int xx[4]={0,0,1,-1}; 29 int yy[4]={1,-1,0,0}; 30 struct node 31 { 32 int x,y,l,r; 33 }e; 34 deque<node>que; 35 int check(int xx,int yy) 36 { 37 if(xx<1||xx>n||yy<1|yy>m||bok[xx][yy]==1||s[xx][yy]=='*') 38 return 0; 39 return 1; 40 } 41 void dfs() 42 { 43 bok[r][c]=1; 44 que.push_front({r,c,L,R}); 45 while(!que.empty()) 46 { 47 e=que.front(); que.pop_front(); 48 //cout<<e.x<<" "<<e.y<<" "<<e.l<<" "<<e.r<<endl; 49 for(int i=2;i<4;i++) 50 { 51 int _x=e.x+xx[i],_y=e.y+yy[i]; 52 if(check(_x,_y)) 53 { 54 bok[_x][_y]=1; 55 que.push_front({_x,_y,e.l,e.r}); 56 } 57 } 58 int _x=e.x+xx[1],_y=e.y+yy[1]; 59 if(check(_x,_y)&&e.l) 60 { 61 bok[_x][_y]=1; 62 que.push_back({_x,_y,e.l-1,e.r}); 63 } 64 _x=e.x+xx[0],_y=e.y+yy[0]; 65 if(check(_x,_y)&&e.r) 66 { 67 bok[_x][_y]=1; 68 que.push_back({_x,_y,e.l,e.r-1}); 69 } 70 } 71 72 } 73 int main() 74 { 75 scanf("%d%d%d%d%d%d",&n,&m,&r,&c,&L,&R); 76 for(int i=1;i<=n;i++) 77 scanf("%s",s[i]+1); 78 dfs(); 79 int ans=0; 80 for(int i=1;i<=n;i++) 81 for(int j=1;j<=m;j++) 82 ans+=bok[i][j]; 83 printf("%d ",ans); 84 85 return 0; 86 }
E. Nastya and Unexpected Guest(CF 1341E)
一条路上从0-n,其中有m个安全点,他们分别是di。给出绿灯时间g红灯时间r
1.在红灯时间上,不能走,且必须在安全点上面。
2.在绿灯时间上,必须走
3.除非到安全点才能够转弯,否则不能。
4.每秒走1m,求到达n的最短时间。
只有在路上完美的度过一个绿灯时间,并且最终点是安全点,才算答案。
设f[i][j] 分别为 到达 d[i] 点时,绿灯时间过了 j 秒,最少的完整红绿灯时间个数。
如果 j==0 且 n-d[i] <=g (当前绿灯时间没有,也就有几个完整的红绿灯时间,从d[i]点出发,能够直接到n点,也就是答案)
ans=min(ans,f[i][j]*(g+r)+n-d[i]); //完整的红绿灯个数*红绿灯时间 ,再加上最后一趟走的时间。
如果 j==g //正好过了一个绿灯时间。也就是正好一个红绿灯轮回
f[i][0]=f[i][j]+1 //个数加一,并且要把这个点放进队列尾端。
que.push_back();
continue;
再从这个点 向左边的安全点 或者右边的安全点 走,转移一下,把这些状态都记录下来,其实是看 是否能走过一个完整的绿灯时间。
f[p][v]=f[i][j] //这时个数不加一,把这个点放进队列开头。
que.push_front();
最后输出答案就好了。 队列里最多有 m*g 个状态。且因为求最优,每个点只会经过一次。
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 #include <set> 6 #include <queue> 7 #include <stack> 8 #include <string> 9 #include <cstring> 10 #include <vector> 11 #include <map> 12 #include<ctime> 13 //#include <unordered_map> 14 #define mem( a ,x ) memset( a , x ,sizeof(a) ) 15 #define rep( i ,x ,y ) for( int i = x ; i<=y ;i++ ) 16 #define lson l ,mid ,pos<<1 17 #define rson mid+1 ,r ,pos<<1|1 18 using namespace std; 19 typedef long long ll ; 20 typedef pair<int ,int> pii; 21 typedef pair<ll ,int> pli; 22 const int inf = 0x3f3f3f3f; 23 const ll mod=998244353; 24 const int N=10000+50; 25 int n,m,d[N],g,r; 26 int bok[N][1010],f[N][1010]; 27 ll ans=-1,res; 28 struct node 29 { 30 int p,v; 31 }e; 32 void dfs() 33 { 34 deque<node>que; 35 bok[0][0]=1; 36 que.push_front({0,0}); 37 while(!que.empty()) 38 { 39 e=que.front(); que.pop_front(); 40 if(e.v==0) 41 { 42 if(n-d[e.p]<=g) 43 { 44 res=1ll*f[e.p][e.v]*(g+r)+n-d[e.p]; 45 if(ans==-1||ans>res) 46 ans=res; 47 } 48 } 49 if(e.v==g) 50 { 51 if(!bok[e.p][0]) 52 { 53 bok[e.p][0]=1; 54 f[e.p][0]=f[e.p][e.v]+1; 55 que.push_back({e.p,0}); 56 } 57 continue; 58 } 59 if(e.p>1) 60 { 61 int p=e.p-1; 62 int v=e.v+d[e.p]-d[p]; 63 if(v<=g&&!bok[p][v]) 64 { 65 bok[p][v]=1; 66 f[p][v]=f[e.p][e.v]; 67 que.push_front({p,v}); 68 } 69 } 70 if(e.p<m) 71 { 72 int p=e.p+1; 73 int v=e.v+d[p]-d[e.p]; 74 if(v<=g&&!bok[p][v]) 75 { 76 bok[p][v]=1; 77 f[p][v]=f[e.p][e.v]; 78 que.push_front({p,v}); 79 } 80 } 81 } 82 printf("%lld ",ans); 83 } 84 int main() 85 { 86 scanf("%d%d",&n,&m); 87 for(int i=1;i<=m;i++) 88 scanf("%d",&d[i]); 89 sort(d+1,d+m+1); 90 scanf("%d%d",&g,&r); 91 dfs(); 92 93 return 0; 94 }
Codeforces 590C Three States