bfs 搜索状态多加一维表示时间
vis[x][y][t]表示t时间能否到达点(x,y)
对于每个士兵,预处理出哪些时间哪些点是不可访问
这题看着提示瞎写一通结果过了。。恍恍惚惚
#include <cstdio> #include <algorithm> #include <set> #include <map> #include <iostream> #include <string> #include <queue> #include <memory.h> using namespace std; int n,m,k,d; char mat[105][105]; int vis[105][105][1005]; int dir[5][2]={-1,0,1,0,0,-1,0,1,0,0}; int ans=20000000; struct point { int x,y,time; point(int xx,int yy,int tt) { x=xx; y=yy; time=tt; } }; void bfs(point po) { queue<point> q; q.push(po); vis[po.x][po.y][po.time]=1; while(!q.empty()) { point p=q.front(); q.pop(); if(p.x==n&&p.y==m) { ans=p.time; break; } for(int i=0;i<5;i++) { int nx=p.x+dir[i][0]; int ny=p.y+dir[i][1]; int ntime=p.time+1; if(nx<0||ny<0||nx>n||ny>m||vis[nx][ny][ntime]||ntime>d) continue; //在此处设置访问 vis[nx][ny][ntime]=1; q.push(point(nx,ny,ntime)); } } } bool cmp(int x,int y) { return x>y; } void print() { for(int k=0;k<=d;k++) { cout<<k<<"时刻:"<<endl; for(int i=0;i<=n;i++) { for(int j=0;j<=m;j++) { cout<<vis[i][j][k]<<" "; } cout<<endl; } } } //bfs 搜索状态多加一维表示时间 //vis[x][y][t]表示t时间能否到达点(x,y) //对于每个士兵,预处理出哪些时间哪些点是不可访问 void solve(char di,int t,int v,int x,int y) { for(int i=0;i<d+1;i++) vis[x][y][i]=1; //上下左右 if(di==‘N‘) { //i代表横坐标 //从第一个射到的点开始 for(int i=1;x-i*v>=0;i++) { //每隔一个周期这个点会再次被射到,即不能通过 for(int j=i;j<=d;j+=t) { vis[x-i*v][y][j]=1; } } } else if(di==‘S‘) { for(int i=1;x+i*v<=n;i++) { for(int j=i;j<=d;j+=t) { vis[x+i*v][y][j]=1; } } } else if(di==‘W‘) { for(int i=1;y-i*v>=0;i++) { for(int j=i;j<=d;j+=t) { vis[x][y-i*v][j]=1; } } } else if(di==‘E‘) { for(int i=1;y+i*v<=m;i++) { for(int j=i;j<=d;j+=t) { vis[x][y+i*v][j]=1; } } } //print(); } int main () { memset(vis,0,sizeof(vis)); cin>>n>>m>>k>>d; char di; int t,v,x,y; for(int i=0;i<k;i++) { cin>>di>>t>>v>>x>>y; solve(di,t,v,x,y); } bfs(point(0,0,0)); if(ans!=20000000) cout<<ans<<endl; else cout<<"Bad luck!"; return 0; }
反向建图,2 遍 bfs。一遍 bfs,求出哪些点能到达终点,然后标记哪些点的所有出边都能到达终点,再一遍 bfs 的时候只访问标记过的点。
这题也是瞎写。。然后过了。。很迷
#include <cstdio> #include <algorithm> #include <set> #include <map> #include <iostream> #include <string> #include <queue> #include <memory.h> using namespace std; int n,m,x,y,s,t; int dir[4][2]={-1,0,1,0,0,-1,0,1}; int ans=-1; //反向存储图 vector<int> mapp1[10005]; //正向存储图 vector<int> mapp2[10005]; //第一次bfs 筛选出能到达终点&&所有的出边指向的点都能到达终点的点 int vis1[10005]; //第二次bfs int vis2[10005]; //存放能到达终点的点 vector<int> point_can1; //存放能到达终点&&所有的出边指向的点都能到达终点的点 vector<int> point_can2; //从终点反向搜索,先选出能到达终点的点 //再从中选出所有的出边指向的点都能到达终点的点 void bfs1(int s,int t) { queue<int> q; q.push(t); vis1[t]=1; while(!q.empty()) { int point=q.front(); q.pop(); for(int i=0;i<mapp1[point].size();i++) { int p=mapp1[point][i]; if(!vis1[p]) { vis1[p]=1; q.push(p); //记录能到达终点的点 point_can1.push_back(p); } } } for(int i=0;i<point_can1.size();i++) { int flag=1; for(int j=0;j<mapp2[point_can1[i]].size();j++) { //如何这个点的出边不能走到终点则此点不可选 if(!vis1[mapp2[point_can1[i]][j]]) { flag=0;break; } } if(flag) point_can2.push_back(point_can1[i]); } } void bfs2() { //如果起点无法到达 直接出 if(count(point_can2.begin(),point_can2.end(),s)==0) return; queue<pair<int,int> > q; q.push(pair<int,int>(s,0)); vis2[s]=1; while(!q.empty()) { pair<int,int> point=q.front(); q.pop(); for(int i=0;i<mapp2[point.first].size();i++) { int next=mapp2[point.first][i]; if(next==t) { ans=point.second+1; return; } //如果下一个点是合法点并且没有被访问过 if(!vis2[next]&&count(point_can2.begin(),point_can2.end(),next)>0) { q.push(pair<int,int>(next,point.second+1)); vis2[next]=1; } } } } int main () { memset(vis1,0,sizeof(vis1)); memset(vis2,0,sizeof(vis2)); cin>>n>>m; for(int i=0;i<m;i++) { cin>>x>>y; mapp2[x].push_back(y); mapp1[y].push_back(x); } cin>>s>>t; bfs1(s,t); bfs2(); cout<<ans<<endl; return 0; }
时间: 2024-10-12 21:50:57