经典迷宫问题:
P6207 [USACO06OCT] Cows on Skates G
1.广搜可用于查找最少需要的步数,而深搜可求出到达终点的路经数。
2.可开一个数组记录路径,最后用深搜回溯路径。注意起点和终点的设置,可能需要自行补上。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int r,c,way[155][155][2];
int dx[4]={-1,1,0,0};
int dy[4]={0,0,1,-1};
char mp[155][155];
bool vis[155][155];
struct node
{
int x,y,s;
};
queue<node>q;
void dfs(int xx,int yy)
{
if(!way[xx][yy][0]&&!way[xx][yy][1]) return;
dfs(way[xx][yy][0],way[xx][yy][1]);
cout<<way[xx][yy][0]<<" "<<way[xx][yy][1]<<endl;
}
signed main()
{
cin>>r>>c;
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
cin>>mp[i][j];
vis[1][1]=1;
q.push(node{1,1,0});
while(!q.empty())
{
node cur=q.front();q.pop();
int x=cur.x,y=cur.y;
if(x==r&&y==c)
break;
for(int i=0;i<4;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(nx<=0||nx>r||ny<=0||ny>c) continue;
if(!vis[nx][ny]&&mp[nx][ny]=='.')
{
vis[nx][ny]=1;
way[nx][ny][0]=x;way[nx][ny][1]=y;
q.push(node{nx,ny,cur.s+1});
}
}
}
dfs(r,c);
cout<<r<<" "<<c<<endl;
return 0;
}
2.动态迷宫问题
P3395 路障
在每秒结束后放上一个路障。
关键关键:::注意yes和no输出的格式,看错了即使全敲对了也零分。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2005;
int n,zx[N],zy[N];
int dx[4]={-1,1,0,0};
int dy[4]={0,0,1,-1};
int mp[N][N];
bool vis[N][N];
struct node
{
int x,y,s;
};
queue<node>q;
signed main()
{
int t;cin>>t;
while(t--)
{
while(!q.empty()) q.pop();
memset(mp,0,sizeof(mp));
memset(vis,0,sizeof(vis));
int n;cin>>n;
for(int i=1;i<=2*n-2;i++)
cin>>zx[i]>>zy[i];
vis[1][1]=1;
q.push(node{1,1,0});
int flag=0;
while(!q.empty())
{
node cur=q.front();q.pop();
int x=cur.x,y=cur.y,g=cur.s;
if(x==n&&y==n)
{
flag=1;break;
}
mp[zx[g]][zy[g]]=1;
for(int i=0;i<4;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(nx<=0||nx>n||ny<=0||ny>n)
continue;
if(!vis[nx][ny]&&!mp[nx][ny])
{
vis[nx][ny]=1;q.push(node{nx,ny,g+1});
}
}
}
if(flag)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
}
广搜的灵活应用:
P3906 Geodetic集合
1.先利用广搜对于每个点进行松弛操作,记录到达这个点最短路径的前驱点。
2.根据终点,和记录的前驱点,遍历回起点,记录遍历过的点,方便输出。
#include<bits/stdc++.h>
#define long long ll
using namespace std;
const int inf=0x3f3f3f3f;
const int N=105;
int n,m,k,g[N][N],dist[N],pre[N][N],num[N];
bool vis[N];
void bfs(int u,int v)
{
memset(num,0,sizeof(num));
memset(dist,inf,sizeof(dist));
memset(vis,0,sizeof(vis));
queue<int>q;dist[u]=0;
q.push(u);
while(!q.empty())
{
int s=q.front();q.pop();
if(vis[s]) continue;
vis[s]=1;
for(int i=1;i<=n;i++)
{
if(g[s][i])
{
if(dist[i]>dist[s]+1)
{
dist[i]=dist[s]+1;
pre[i][++num[i]]=s;
q.push(i);
}
else if(dist[i]==dist[s]+1)
pre[i][++num[i]]=s;
}
}
}
memset(vis,0,sizeof(vis));
q.push(v);vis[v]=1;
while(!q.empty())
{
int s=q.front();q.pop();
for(int i=num[s];i>=1;i--)
{
if(!vis[pre[s][i]])
{
vis[pre[s][i]]=1;
q.push(pre[s][i]);
}
}
}
for(int i=1;i<=n;i++)
if(vis[i])
cout<<i<<" ";
cout<<endl;
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v;cin>>u>>v;
g[u][v]=g[v][u]=1;
}
cin>>k;
while(k--)
{
int u,v;cin>>u>>v;
bfs(u,v);
}
return 0;
}
深搜经典题目:
P2196 [NOIP1996 提高组] 挖地雷
#include<bits/stdc++.h>
#define long long ll
using namespace std;
const int inf=0x3f3f3f3f;
const int N=55;
int n,a[N],g[N][N],path[N],ans[N],mx,gg;
bool vis[N];
bool check(int u)
{
for(int i=1;i<=n;i++)
{
if(g[u][i]&&!vis[i])
return 1;
}
return 0;
}
void dfs(int id,int step,int sum)
{
if(!check(id))
{
if(mx<sum)
{
mx=sum;gg=step;
for(int i=1;i<=step;i++) ans[i]=path[i];
}
}
for(int i=1;i<=n;i++)
{
if(g[id][i]&&!vis[i])
{
path[step+1]=i;
vis[i]=1;
dfs(i,step+1,sum+a[i]);
vis[i]=0;
}
}
}
signed main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
{
int x;cin>>x;
if(x)
g[i][j]=1;
}
for(int i=1;i<=n;i++)
{
path[1]=i;
vis[i]=1;
dfs(i,1,a[i]);
vis[i]=0;
}
for(int i=1;i<=gg;i++)
cout<<ans[i]<<" ";
cout<<endl;
cout<<mx<<endl;
return 0;
}
P2920 [USACO08NOV]Time Management S
二分枚举起点。注意特判-1的情况!!
#include<bits/stdc++.h>
#define long long ll
using namespace std;
const int inf=0x3f3f3f3f;
const int N=1005;
int n,ans,mx=inf;
struct work
{
int st,ti,ed;
}e[N];
bool cmp(work e1,work e2)
{
return e1.ed<e2.ed;
}
bool check(int x)
{
for(int i=1;i<=n;i++)
{
x+=e[i].ti;
if(x>e[i].ed)
return 0;
}
return 1;
}
signed main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>e[i].ti>>e[i].ed;
e[i].st=e[i].ed-e[i].ti;
mx=min(mx,e[i].st);
}
sort(e+1,e+n+1,cmp);
int l=0,r=mx;
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid))
ans=mid,l=mid+1;
else
r=mid-1;
}
if(ans)
cout<<ans<<endl;
else
cout<<-1<<endl;
return 0;
}
P1419 寻找段落
二分答案+单调队列
题意:在一个固定的序列中,找到一个长度在s到t的连续序列,使得其平均值最大。
思路:构造一个函数f(x),呈现单调不递增的性质。当x小时为1;x越大,越会为0。在函数中,
我们将a全部减去mid,问题转化为判断是否存在一个长度在s~t范围内的区间它的和为正,如果有说明还有更大的平均值。
用前缀和和单调队列维护。
然后用单调队列求出sum[i]-min(sum[i-t]~sum[i-s]),然后判断是否大于0即可
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=1e5+5;
int n,s,t,a[N];
double ans,sum[N];
bool check(double x)
{
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+double(a[i])-x;
int head=1,tail=0,q[N];
for(int i=s;i<=n;i++)
{
while(head<=tail&&sum[q[tail]]>sum[i-s])
tail--;
q[++tail]=i-s;
while(head<=tail&&q[head]<i-t)
head++;
if(head<=tail&&sum[i]-sum[q[head]]>=0)
return 1;
}
return 0;
}
signed main()
{
cin>>n>>s>>t;
for(int i=1;i<=n;i++)
cin>>a[i];
double l=-10000,r=10000;
while(r-l>1e-5)
{
double mid=(l+r)/2;
if(check(mid))
ans=mid,l=mid;
else
r=mid;
}
printf("%.3lf\n", ans);
return 0;
}