A-棋盘问题 dfs
1.dfs进入时打上标记,退出时清除,不需要额外的状态记录
2.可行性剪枝,减小常数
3.用r[i],c[j]表示行和列的占用情况,减小常数
#include<bits/stdc++.h>
using namespace std;
int n,k;
char g[10][10];
int r[10],c[10];
int top,ans;
pair<int,int> id[10]; //第i个空位的坐标
inline bool ok(int i,int j){
if(r[i]==0&&c[j]==0)
return 1;
return 0;
}
void dfs(int idx,int pl,int res){
//printf("idx=%d pl=%d res=%d\n",idx,pl,res);
if(idx==top){
if(pl==0&&res==0){
ans++;
/*for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
printf("%c",g[i][j]);
}
printf("\n");
}
printf("ans++\n");*/
}
return;
}
if(top-idx<res){
//可行性剪枝
//即使后面的都放也没办法放完
return;
}
if(pl==1){
if(res==0)
return;
/*for(int i=0;i<n;i++){
if(g[i][id[idx].second]=='$')
return;
}
for(int j=0;j<n;j++){
if(g[id[idx].first][j]=='$')
return;
}*/
if(ok(id[idx].first,id[idx].second)){
//g[id[idx].first][id[idx].second]='$';
r[id[idx].first]=1;
c[id[idx].second]=1;
dfs(idx+1,0,res-1);
dfs(idx+1,1,res-1);
//g[id[idx].first][id[idx].second]='#';
r[id[idx].first]=0;
c[id[idx].second]=0;
}
else{
return;
}
}
else{
dfs(idx+1,0,res);
dfs(idx+1,1,res);
}
}
int main(){
while(1){
scanf("%d%d",&n,&k);
if(n==-1)
break;
for(int i=0;i<n;i++){
scanf("%s",g[i]);
r[i]=0;
c[i]=0;
}
top=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(g[i][j]=='#'){
id[top++]={i,j};
}
}
}
ans=0;
if(k){
dfs(0,0,k);
dfs(0,1,k);
}
printf("%d\n",ans);
}
}
B - Dungeon Master bfs
第一次不看书写bfs,犯了一些错误
1.写成了dfs,妄想递归调用自己(应该在循环里解决整个bfs过程)
2.某个格子入队后没有加上标记,导致其重复入队(一个节点应分为:0-未访问,1-已出队,2-已入队)
3.写法非常难看
4.队列没有clear()方法,只能一个一个弹出
#include<bits/stdc++.h>
using namespace std;
int L,R,C;
char g[32][32][32];
int vis[32][32][32];
struct cor{
int l,r,c,m;
cor(int ll=0,int rr=0,int cc=0,int mm=0){
l=ll,r=rr,c=cc;
m=mm;
}
};
int ans;
queue<cor> Q;
bool inRange(int l,int r,int c,int m){
if(l<0||l>=L||r<0||r>=R||c<0||c>=C)
return 0;
if(g[l][r][c]=='#')
return 0;
if(vis[l][r][c]!=0)
return 0;
vis[l][r][c]=2;
Q.push(cor(l,r,c,m));
return 1;
}
void bfs(int l,int r,int c,int m){
if(ans!=-1)
return;
if(l<0||l>=L||r<0||r>=R||c<0||c>=C)
return;
if(vis[l][r][c]!=0)
return;
if(g[l][r][c]=='E'){
ans=m;
return;
}
if(g[l][r][c]=='#')
return;
Q.push(cor(l,r,c));
while(!Q.empty()){
cor c1=Q.front();
vis[c1.l][c1.r][c1.c]=1;
if(g[c1.l][c1.r][c1.c]=='E'){
ans=c1.m;
return;
}
Q.pop();
inRange(c1.l-1,c1.r,c1.c,c1.m+1);
inRange(c1.l-1,c1.r,c1.c,c1.m+1);
inRange(c1.l+1,c1.r,c1.c,c1.m+1);
inRange(c1.l,c1.r-1,c1.c,c1.m+1);
inRange(c1.l,c1.r+1,c1.c,c1.m+1);
inRange(c1.l,c1.r,c1.c-1,c1.m+1);
inRange(c1.l,c1.r,c1.c+1,c1.m+1);
}
}
int main(){
while(1){
scanf("%d%d%d",&L,&R,&C);
if(L==0)
break;
while(!Q.empty())
Q.pop();
memset(vis,0,sizeof(vis));
for(int l=0;l<L;l++){
for(int r=0;r<R;r++){
scanf("%s",g[l][r]);
}
}
ans=-1;
for(int l=0;l<L;l++){
for(int r=0;r<R;r++){
for(int c=0;c<C;c++){
if(g[l][r][c]=='S'){
bfs(l,r,c,0);
break;
}
}
}
}
if(ans>=0){
printf("Escaped in %d minute(s).\n",ans);
}
else{
puts("Trapped!");
}
}
}
修改得好看一点,改成一个enqueue()函数,在enqueue()函数里判断越界、重复和搜索完成。dequeue()函数则不是很有用。
#include<bits/stdc++.h>
using namespace std;
int L,R,C;
char g[32][32][32];
int vis[32][32][32];
struct cor{
int l,r,c,m;
cor(int ll=0,int rr=0,int cc=0,int mm=0){
l=ll,r=rr,c=cc;
m=mm;
}
};
int ans;
queue<cor> Q;
inline bool enqueue(int l,int r,int c,int m){
if(ans!=-1){
return 1;
}
if(l<0||l>=L||r<0||r>=R||c<0||c>=C)
return 0;
if(g[l][r][c]=='#')
return 0;
if(vis[l][r][c]!=0)
return 0;
vis[l][r][c]=2;
if(g[l][r][c]=='E'){
ans=m;
return 1;
}
Q.push(cor(l,r,c,m));
return 1;
}
inline bool dequeue(){
if(Q.empty())
return 0;
else{
cor c1=Q.front();
vis[c1.l][c1.r][c1.c]=1;
Q.pop();
}
}
void bfs(){
while(!Q.empty()){
cor c1=Q.front();
dequeue();
enqueue(c1.l-1,c1.r,c1.c,c1.m+1);
enqueue(c1.l-1,c1.r,c1.c,c1.m+1);
enqueue(c1.l+1,c1.r,c1.c,c1.m+1);
enqueue(c1.l,c1.r-1,c1.c,c1.m+1);
enqueue(c1.l,c1.r+1,c1.c,c1.m+1);
enqueue(c1.l,c1.r,c1.c-1,c1.m+1);
enqueue(c1.l,c1.r,c1.c+1,c1.m+1);
if(ans!=-1)
return;
}
}
int main(){
while(1){
scanf("%d%d%d",&L,&R,&C);
if(L==0)
break;
while(!Q.empty())
Q.pop();
memset(vis,0,sizeof(vis));
for(int l=0;l<L;l++){
for(int r=0;r<R;r++){
scanf("%s",g[l][r]);
}
}
ans=-1;
for(int l=0;l<L;l++){
for(int r=0;r<R;r++){
for(int c=0;c<C;c++){
if(g[l][r][c]=='S'){
Q.push(cor(l,r,c,0));
break;
}
}
}
}
bfs();
if(ans>=0){
printf("Escaped in %d minute(s).\n",ans);
}
else{
puts("Trapped!");
}
}
}
C - Catch That Cow
看上去就是bfs瞎改一下的样子,不知道对不对。(有点像今天看的机器人炸城市的dijkstra算法,瞎改一下)
#include<bits/stdc++.h>
using namespace std;
int n,k;
int vis[200005];
struct cor{
int x;
int t;
cor(int xx=0,int tt=0){
x=xx,t=tt;
}
};
queue<cor> Q;
void enqueue(int x,int t){
if(x<0||x>200000){
return;
}
if(vis[x]!=-1)
return;
vis[x]=t;
Q.push(cor(x,t));
}
void bfs(){
vis[n]=0;
Q.push(cor(n,0));
while(!Q.empty()){
cor c=Q.front();
int x=c.x;
int t=c.t;
Q.pop();
enqueue(x-1,t+1);
enqueue(x+1,t+1);
enqueue(2*x,t+1);
}
}
int main(){
while(~scanf("%d%d",&n,&k)){
memset(vis,-1,sizeof(vis));
bfs();
printf("%d\n",vis[k]);
}
}
D
E - Find The Multiple 各种搜索
dfs发现198会T,尝试改成bfs没想到爆了ll,改成string效率感人但是还是交了一发,果然T了。怒打表。
打表发现最长的198也是19位长度,在ull的范围内(但是爆ll)。被题面欺诈了,北大果然喜欢题面欺诈(某jls)。难道真的只能先打表吗?已经知道ull不会爆之后尝试的ull写法。也是T了(估计是取模次数太多),连清空队列的时间都不够。下面是重定向到表再复制进来。注释里的是正解。意思是不打表就不会知道ull不会爆?太坑爹了。我都把表打出来了不是乱搞就可以过吗?
#include<bits/stdc++.h>
using namespace std;
#define ll long long
/*
int n;
string ans;
int maxn;
struct num{
string d;
int re;
num();
num(string dd,int ree){
d=dd;
re=ree;
}
};
queue<num> Q;
void bfs(){
Q.push(num("",0));
while(!Q.empty()){
string s=Q.front().d;
//cout<<s<<endl;
int re=Q.front().re;
int l=s.length();
int r=1;
for(int i=0;i<l;i++){
r*=10;
r%=n;
}
int re2=(re+r)%n;
if(re2==0){
ans='1'+s;
return;
}
Q.pop();
Q.push(num(string('0'+s),re));
Q.push(num(string('1'+s),re2));
}
}
int main(){
freopen("E.out","w",stdout);
for(int i=1;i<=200;i++){
n=i;
if(n==0)
break;
ans="";
while(!Q.empty()){
Q.pop();
}
bfs();
cout<<"\""<<ans<<"\",";
}
}
*/
string ans[]={"1","10","111","100","10","1110","1001","1000","111111111","10","11","11100","1001",
"10010","1110","10000","11101","1111111110","11001","100","10101","110","110101",
"111000","100","10010","1111111101","100100","1101101","1110","111011","100000",
"111111","111010","10010","11111111100","111","110010","10101","1000","11111",
"101010","1101101","1100","1111111110","1101010","10011","1110000","1100001","100",
"100011","100100","100011","11111111010","110","1001000","11001","11011010",
"11011111","11100","100101","1110110","1111011111","1000000","10010","1111110",
"1101011","1110100","11111001","10010","10011","111111111000","10001","1110","11100",
"1100100","1001","101010","11101001","10000","1111111101","111110","101011",
"1010100","111010","11011010","11010111","11000","11010101","1111111110","1001",
"11010100","10000011","100110","110010","11100000","11100001","11000010",
"111111111111111111","100","101","1000110","11100001","1001000","101010","1000110",
"100010011","111111110100","1111111011","110","111","10010000","1011011","110010",
"1101010","110110100","11111110101","110111110","110001101","111000","11011",
"1001010","10011100011","11101100","1000","11110111110","11010011","10000000",
"100100001","10010","101001","11111100","11101111","11010110","11111111010",
"11101000","10001","111110010","110110101","100100","10011","100110","1001",
"1111111110000","11011010","100010","1100001","11100","110111","11100","1110001",
"11001000","11111011011","10010","1110110","1010100","10101101011","111010010",
"100011","100000","11101111","11111111010","1010111","1111100","1111110","1010110",
"11111011","10101000","10111101","111010","1111011111","110110100","1011001101",
"110101110","100100","110000","101110011","110101010","11010111","11111111100",
"1001111","10010","100101","110101000","1110","100000110","1001011","1001100",
"1111111100001","110010","11101111","111000000","11001","111000010","101010",
"110000100","1101000101","1111111111111111110","111000011","1000"};
int main(){
int n;
while(cin>>n,n){
cout<<ans[n-1]<<endl;
}
}
F - Prime Path
居然把“只有一位数字不同”写成了两个数的差是1~9,10~90,100~900,1000~9000,有毒。然后还交了一发TLE因为是while的t和后面的t重名了,说明以后T组数据还是写大写的T吧。把邻接矩阵改成邻接向量并搜索到答案就退出,时间从235ms优化到79ms,说明影响还是很大的,改成双向广搜会不会更快?(写了一个不判Impossible的居然过了???)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int prime[10000];
int top=0;
vector<int> g[1100];
int vis[1100]={};
int p[1100]={};
bool isPrime(int p){
int cei=(sqrt(double(p)));
for(int i=2;i<=cei;i++){
if(p%i==0){
return 0;
}
}
return 1;
}
int a[4];
void init(){
for(int i=1000;i<=9999;i++){
int p=i;
if(isPrime(p)){
prime[top++]=p;
}
else{
;
}
}
//cout<<top<<endl;
for(int i=0;i<top;i++){
for(int j=i+1;j<top;j++){
int l1=prime[j]%10==prime[i]%10;
int l2=prime[j]/10%10==prime[i]/10%10;
int l3=prime[j]/100%10==prime[i]/100%10;
int l4=prime[j]/1000%10==prime[i]/1000%10;
if(l1&&l2&&l3||l1&&l2&&l4||l1&&l4&&l3||l4&&l2&&l3){
//if(prime[i]==1009||prime[j]==1009)
//cout<<prime[i]<<" "<<prime[j]<<endl;
g[i].push_back(j);
g[j].push_back(i);
}
}
}
}
int s,t;
int sid,tid;
queue<int> Q;
void bfs(){
vis[sid]=0;
Q.push(sid);
int suc=0;
while(!Q.empty()){
int id=Q.front();
//cout<<prime[id]<<" "<<vis[id]<<" "<<p[id]<<endl;
Q.pop();
int l=g[id].size();
for(int i=0;i<l;i++){
if(vis[g[id][i]]==-1){
vis[g[id][i]]=vis[id]+1;
if(g[id][i]==tid){
suc=1;
break;
}
p[g[id][i]]=prime[id];
Q.push(g[id][i]);
}
if(suc==1){
break;
}
}
}
while(!Q.empty()){
Q.pop();
}
}
int main(){
init();
int T;
while(~scanf("%d",&T)){
for(int i=0;i<T;i++){
scanf("%d%d",&s,&t);
memset(vis,-1,sizeof(vis));
sid=lower_bound(prime,prime+top,s)-prime;
tid=lower_bound(prime,prime+top,t)-prime;
bfs();
//printf("p=%d ",prime[tid]);
if(vis[tid]!=-1)
printf("%d\n",vis[tid]);
else{
printf("Impossible\n");
}
}
}
}
G - Shuffle'm Up dbfs
没有注意到每次只有一种转移,以为状态数会很多,就写了一个dbfs,发现第一次写问题还是蛮多的,首先就是控制两边的深度平衡,但同时要保证是非空的队列才能操作,每次操作完应该可以更新深度也可以不更新。反向搜索时要注意状态是反向转移的。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
string ss,st;
map<string,int>m1;
map<string,int>m2;
queue<pair<string,int> >q1;
queue<pair<string,int> >q2;
int C;
int len;
string s,ns;
int ans;
void dbfs(){
int t1=0,t2=0;
m1[ss]=t1;
m2[st]=t2;
q1.push({ss,t1});
q2.push({st,t2});
while(!q1.empty()||!q2.empty()){
if(t1<=t2&&!q1.empty()){
s=q1.front().first;
//cout<<"s1="<<s<<endl;
q1.pop();
ns.resize(len);
for(int i=0;i<len;i++){
if(i%2==0){
ns[i]=s[C+i/2];
}
else{
ns[i]=s[i/2];
}
}
//cout<<"ns1="<<ns<<endl;
if(m2.count(ns)){
ans=m2[ns]+t1+1;
return;
}
if(m1.count(ns)==0){
q1.push({ns,t1+1});
m1[ns]=t1+1;
t1=q1.front().second;
}
}
else if(!q2.empty()){
s=q2.front().first;
//cout<<"s2="<<s<<endl;
q2.pop();
ns.resize(len);
//这里应该是倒退步骤
for(int i=0;i<C;i++){
ns[i]=s[2*i+1];
}
for(int i=C;i<len;i++){
ns[i]=s[2*(i-C)];
}
if(m1.count(ns)){
ans=m1[ns]+t2+1;
return;
}
if(m2.count(ns)==0){
q2.push({ns,t2+1});
m2[ns]=t2+1;
t2=q2.front().second;
}
}
else{
s=q1.front().first;
//cout<<"s1="<<s<<endl;
q1.pop();
ns.resize(len);
for(int i=0;i<len;i++){
if(i%2==0){
ns[i]=s[C+i/2];
}
else{
ns[i]=s[i/2];
}
}
//cout<<"ns1="<<ns<<endl;
if(m2.count(ns)){
ans=m2[ns]+t1+1;
return;
}
if(m1.count(ns)==0){
q1.push({ns,t1+1});
m1[ns]=t1+1;
t1=q1.front().second;
}
}
}
}
int main(){
int T;
while(~scanf("%d",&T)){
for(int t=1;t<=T;t++){
m1.clear();
m2.clear();
while(!q1.empty()) q1.pop();
while(!q2.empty()) q2.pop();
scanf("%d",&C);
len=2*C;
string s1,s2;
cin>>s1>>s2>>st;
ss=s1+s2;
if(ss==st){
printf("%d %d\n",t,0);
continue;
}
ans=-1;
dbfs();
printf("%d %d\n",t,ans);
}
}
}
H - Pots bfs
好几个点差点弄错了。比如gett[C]找到会会被下一次覆盖,比如impossible,比如一开始是空pot,比如用memset来给pair和string赋值?还有一个是交上去错了是DROP(1,2)忘记改过来?!所以说这种需要还原步骤的应该怎么写呢?最后还是用一个struct来写吧。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int A,B,C;
int a,b;
pair<int,string> g[105][105];
pair<int,int> f[105][105];
int gett[105];
int gettCa,gettCb;
pair<pair<int,int>,int> p;
queue<pair<pair<int,int>,int> > Q;
void bfs(){
while(!Q.empty())
Q.pop();
Q.push({{0,0},0});
g[0][0]={0,""};
while(!Q.empty()){
a=Q.front().first.first;
b=Q.front().first.second;
//cout<<a<<" "<<b<<" "<<g[a][b].second<<endl;
int pt=Q.front().second;
Q.pop();
if(pt+1<g[A][b].first){
g[A][b].first=pt+1;
Q.push({{A,b},pt+1});
g[A][b].second="FILL(1)";
f[A][b]={a,b};
gett[A]=1;
gett[b]=1;
if(gett[C]==1){
gettCa=A;
gettCb=b;
while(!Q.empty()){
Q.pop();
}
return;
}
}
if(pt+1<g[a][B].first){
g[a][B].first=pt+1;
g[a][B].second="FILL(2)";
Q.push({{a,B},pt+1});
f[a][B]={a,b};
gett[a]=1;
gett[B]=1;
if(gett[C]==1){
gettCa=a;
gettCb=B;
while(!Q.empty()){
Q.pop();
}
return;
}
}
if(pt+1<g[0][b].first){
g[0][b].first=pt+1;
g[0][b].second="DROP(1)";
Q.push({{0,b},pt+1});
f[0][b]={a,b};
gett[0]=1;
gett[b]=1;
if(gett[C]==1){
gettCa=0;
gettCb=b;
while(!Q.empty()){
Q.pop();
}
return;
}
}
if(pt+1<g[a][0].first){
g[a][0].first=pt+1;
g[a][0].second="DROP(2)";
Q.push({{a,0},pt+1});
f[a][0]={a,b};
gett[a]=1;
gett[0]=1;
if(gett[C]==1){
gettCa=a;
gettCb=0;
while(!Q.empty()){
Q.pop();
}
return;
}
}
int da=a-min(a,B-b);
int db=b+min(a,B-b);
if(pt+1<g[da][db].first){
g[da][db].first=pt+1;
g[da][db].second="POUR(1,2)";
Q.push({{da,db},pt+1});
f[da][db]={a,b};
gett[da]=1;
gett[db]=1;
if(gett[C]==1){
gettCa=da;
gettCb=db;
while(!Q.empty()){
Q.pop();
}
return;
}
}
da=a+min(A-a,b);
db=b-min(A-a,b);
if(pt+1<g[da][db].first){
g[da][db].first=pt+1;
g[da][db].second="POUR(2,1)";
Q.push({{da,db},pt+1});
f[da][db]={a,b};
gett[da]=1;
gett[db]=1;
if(gett[C]==1){
gettCa=da;
gettCb=db;
while(!Q.empty()){
Q.pop();
}
return;
}
}
if(gett[C]==1){
while(!Q.empty()){
Q.pop();
}
break;
}
}
}
int main(){
while(~scanf("%d%d%d",&A,&B,&C)){
for(int i=0;i<105;i++){
for(int j=0;j<105;j++){
g[i][j].first=0x3f3f3f3f;
}
}
memset(gett,0,sizeof(gett));
bfs();
if(gett[C]==1){
string ans;
int cnt=0;
int cura=gettCa,curb=gettCb;
while(cura!=0||curb!=0){
//cout<<ans<<endl;
ans=g[cura][curb].second+'\n'+ans;
int copycura=cura;
cura=f[cura][curb].first;
curb=f[copycura][curb].second;
cnt++;
}
printf("%d\n",cnt);
cout<<ans;
}
else{
puts("impossible");
}
}
}
I - Fire! bfs
读错题(原本没读错)以为只有一堆火,最后又把火是无穷判作不合法。
以后bfs还在专门写个enqueue函数来做比较方便,而且vis数组要规定墙是-1,待扩展是无穷。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int N,M;
char g[1005][1005];
int tf[1005][1005];
int tj[1005][1005];
struct cor{
int i,j,t;
char c;
cor(int ii=0,int jj=0,int tt=0,char cc=' '){
i=ii,j=jj,t=tt;
c=cc;
}
};
queue<cor> Q;
int ji,jj;
int fi[1005*1005],fj[1005*1005];
int cntf;
void bfs(){
while(!Q.empty()){
Q.pop();
}
for(int i=0;i<cntf;i++){
tf[fi[i]][fj[i]]=0;
Q.push(cor(fi[i],fj[i],0,'F'));
}
while(!Q.empty()){
cor c=Q.front();
Q.pop();
if(c.i>0&&tf[c.i-1][c.j]==0x3f3f3f3f){
tf[c.i-1][c.j]=c.t+1;
Q.push(cor(c.i-1,c.j,c.t+1,'F'));
}
if(c.i+1<N&&tf[c.i+1][c.j]==0x3f3f3f3f){
tf[c.i+1][c.j]=c.t+1;
Q.push(cor(c.i+1,c.j,c.t+1,'F'));
}
if(c.j>0&&tf[c.i][c.j-1]==0x3f3f3f3f){
tf[c.i][c.j-1]=c.t+1;
Q.push(cor(c.i,c.j-1,c.t+1,'F'));
}
if(c.j+1<M&&tf[c.i][c.j+1]==0x3f3f3f3f){
tf[c.i][c.j+1]=c.t+1;
Q.push(cor(c.i,c.j+1,c.t+1,'F'));
}
}
tj[ji][jj]=0;
Q.push(cor(ji,jj,0,'J'));
while(!Q.empty()){
cor c=Q.front();
Q.pop();
if(c.i>0&&tj[c.i-1][c.j]==0x3f3f3f3f){
tj[c.i-1][c.j]=c.t+1;
Q.push(cor(c.i-1,c.j,c.t+1,'J'));
}
if(c.i+1<N&&tj[c.i+1][c.j]==0x3f3f3f3f){
tj[c.i+1][c.j]=c.t+1;
Q.push(cor(c.i+1,c.j,c.t+1,'J'));
}
if(c.j>0&&tj[c.i][c.j-1]==0x3f3f3f3f){
tj[c.i][c.j-1]=c.t+1;
Q.push(cor(c.i,c.j-1,c.t+1,'J'));
}
if(c.j+1<M&&tj[c.i][c.j+1]==0x3f3f3f3f){
tj[c.i][c.j+1]=c.t+1;
Q.push(cor(c.i,c.j+1,c.t+1,'J'));
}
}
/*printf("F:\n");
for(int i=0;i<N;i++){
for(int j=0;j<M;j++){
printf(" %d",tf[i][j]);
}
printf("\n");
}
printf("J:\n");
for(int i=0;i<N;i++){
for(int j=0;j<M;j++){
printf(" %d",tj[i][j]);
}
printf("\n");
}*/
}
int main(){
int T;
while(~scanf("%d",&T)){
while(T--){
scanf("%d%d",&N,&M);
for(int i=0;i<N;i++){
scanf("%s",g[i]);
}
cntf=0;
for(int i=0;i<N;i++){
for(int j=0;j<M;j++){
if(g[i][j]=='#'){
tf[i][j]=-1;
tj[i][j]=-1;
}
else{
tf[i][j]=0x3f3f3f3f;
tj[i][j]=0x3f3f3f3f;
if(g[i][j]=='F'){
fi[cntf]=i;fj[cntf]=j;
cntf++;
}
else if(g[i][j]=='J'){
ji=i,jj=j;
}
}
}
}
bfs();
int mint=0x3f3f3f3f;
for(int i=0;i<N;i++){
if(tf[i][0]>=0&&tj[i][0]>=0&&tj[i][0]!=0x3f3f3f3f){
if(tj[i][0]<tf[i][0]){
mint=min(mint,tj[i][0]);
}
}
if(tf[i][M-1]>=0&&tj[i][M-1]>=0&&tj[i][M-1]!=0x3f3f3f3f){
if(tj[i][M-1]<tf[i][M-1]){
mint=min(mint,tj[i][M-1]);
}
}
}
for(int j=0;j<M;j++){
if(tf[0][j]>=0&&tj[0][j]>=0&&tj[0][j]!=0x3f3f3f3f){
if(tj[0][j]<tf[0][j]){
mint=min(mint,tj[0][j]);
}
}
if(tf[N-1][j]>=0&&tj[N-1][j]>=0&&tj[N-1][j]!=0x3f3f3f3f){
if(tj[N-1][j]<tf[N-1][j]){
mint=min(mint,tj[N-1][j]);
}
}
}
if(mint!=0x3f3f3f3f){
printf("%d\n",mint+1);
}
else{
printf("IMPOSSIBLE\n");
}
}
}
}
J - 迷宫问题 bfs
打个标记表示来自哪个方向即可,用stack回溯。想着进阶搜索里也耍这个花招,呵呵,死得很惨。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n;
int g[6][6];
int vis[6][6];
int di[6][6];
struct cor{
int i,j;
int t;
char d;
//from u,d,l,r
cor(){}
cor(int ii,int jj,int tt,char dd):i(ii),j(jj),t(tt),d(dd){}
};
queue<cor> Q;
void enqueue(int i,int j,int t,int d){
if(i<0||i>=5)
return;
if(j<0||j>=5)
return;
if(vis[i][j]!=0)
return;
vis[i][j]=2;
Q.push(cor(i,j,t,d));
}
void bfs(){
Q.push(cor(0,0,0,'o'));
while(!Q.empty()){
cor c=Q.front();
vis[c.i][c.j]=3;
di[c.i][c.j]=c.d;
Q.pop();
enqueue(c.i-1,c.j,c.t+1,'d');
enqueue(c.i+1,c.j,c.t+1,'u');
enqueue(c.i,c.j-1,c.t+1,'r');
enqueue(c.i,c.j+1,c.t+1,'l');
}
}
void output(){
stack<string>ans;
ans.push("(4, 4)");
int i=4,j=4;
while(i||j){
if(di[i][j]=='u')
i--;
else if(di[i][j]=='d')
i++;
else if(di[i][j]=='l')
j--;
else
j++;
string s="(";
s+=char('0'+i);
s+=", ";
s+=char('0'+j);
s+=')';
ans.push(s);
}
while(!ans.empty()){
cout<<ans.top()<<endl;
ans.pop();
}
}
int main(){
while(~scanf("%d",&g[0][0])){
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
if(i+j){
scanf("%d",&g[i][j]);
}
vis[i][j]=g[i][j];
}
}
bfs();
output();
}
}
K - Oil Deposits dfs/bfs
想起来,去年我最喜欢这题了。记得清空vis和进入dfs前判断vis就好。dfs应该比较好写?
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m;
char g[105][105];
int vis[105][105];
void dfs(int i,int j){
if(i<0||i>=n)
return;
if(j<0||j>=m)
return;
if(vis[i][j]!=0)
return;
vis[i][j]=1;
if(g[i][j]=='@'){
for(int di=-1;di<=1;di++){
for(int dj=-1;dj<=1;dj++){
dfs(i+di,j+dj);
}
}
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
if(n==0)
break;
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++){
scanf("%s",&g[i]);
}
int ans=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(g[i][j]=='@'&&vis[i][j]==0){
ans++;
dfs(i,j);
}
}
}
printf("%d\n",ans);
}
}
L - 非常可乐 bfs
很有趣的一个题目,搞清楚倒可乐的转移步骤就很好写。这个还好,可以用数组表示,假如再大的话是不是要用set来计重了?总之所有的最短次数都是用bfs没跑了。(注意memset确实是以1字节为单位赋值的,可以memset(g,0x3f,sizeof(g))
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int S,N,M;
int g[105][105][105];
struct sta{
int s,n,m,t;
sta(){};
sta(int ss,int nn,int mm,int tt){
s=ss,n=nn,m=mm,t=tt;
}
}s1;
queue<sta> Q;
void enqueue(int s,int n,int m,int t){
//cout<<s<<" "<<n<<" "<<m<<endl;
if(g[s][n][m]==0x3f3f3f3f){
g[s][n][m]=t;
Q.push(sta(s,n,m,t));
}
else
;
}
void bfs(){
while(!Q.empty())
Q.pop();
Q.push(sta(S,0,0,0));
while(!Q.empty()){
s1=Q.front();
Q.pop();
//cout<<s1.s<<" "<<s1.n<<" "<<s1.m<<endl;
int t=s1.t;
enqueue(s1.s-min(s1.s,N-s1.n),s1.n+min(s1.s,N-s1.n),s1.m,t+1);
enqueue(s1.s-min(s1.s,M-s1.m),s1.n,s1.m+min(s1.s,M-s1.m),t+1);
enqueue(s1.s,s1.n-min(s1.n,M-s1.m),s1.m+min(s1.n,M-s1.m),t+1);
enqueue(s1.s+min(S-s1.s,s1.n),s1.n-min(s1.n,S-s1.s),s1.m,t+1);
enqueue(s1.s+min(S-s1.s,s1.m),s1.n,s1.m-min(s1.m,S-s1.s),t+1);
enqueue(s1.s,s1.n+min(N-s1.n,s1.m),s1.m-min(N-s1.n,s1.m),t+1);
}
}
int main(){
while(~scanf("%d%d%d",&S,&N,&M)){
if(S==0&&N==0&&M==0)
break;
if(S%2){
puts("NO");
continue;
}
memset(g,0x3f,sizeof(g));
int ans=0x3f3f3f3f;
bfs();
ans=min(g[S/2][S/2][0],g[0][S/2][S/2]);
ans=min(g[S/2][0][S/2],ans);
if(ans==0x3f3f3f3f)
puts("NO");
else
printf("%d\n",ans);
}
}
M - Find a way bfs
我居然WA2了,没有解决KFC不能到的情况,然后把vis从0变成-1之后还是有问题,说明以后应该默认把距离改成无穷。也就是-1表示不能扩展,inf表示待扩展,正常的非负数表示距离。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m;
char g[205][205];
int vis1[205][205];
int vis2[205][205];
struct cor{
int i,j,t,c;
cor(int ii=0,int jj=0,int tt=0,int cc=0){
i=ii,j=jj,t=tt,c=cc;
}
};
queue<cor> Q;
int mind;
int yi,yj;
int mi,mj;
void bfs(){
vis1[yi][yj]=-1;
Q.push(cor(yi,yj,0,1));
vis2[mi][mj]=-1;
Q.push(cor(mi,mj,0,2));
while(!Q.empty()){
cor c=Q.front();
//cout<<c.i<<" "<<c.j<<" "<<c.c<<endl;
Q.pop();
if(c.c==1){
if(c.i>0&&vis1[c.i-1][c.j]==0){
vis1[c.i-1][c.j]=c.t+1;
Q.push(cor(c.i-1,c.j,c.t+1,1));
}
if(c.i+1<n&&vis1[c.i+1][c.j]==0){
vis1[c.i+1][c.j]=c.t+1;
Q.push(cor(c.i+1,c.j,c.t+1,1));
}
if(c.j>0&&vis1[c.i][c.j-1]==0){
vis1[c.i][c.j-1]=c.t+1;
Q.push(cor(c.i,c.j-1,c.t+1,1));
}
if(c.j+1<m&&vis1[c.i][c.j+1]==0){
vis1[c.i][c.j+1]=c.t+1;
Q.push(cor(c.i,c.j+1,c.t+1,1));
}
}
else if(c.c==2){
if(c.i>0&&vis2[c.i-1][c.j]==0){
vis2[c.i-1][c.j]=c.t+1;
Q.push(cor(c.i-1,c.j,c.t+1,2));
}
if(c.i+1<n&&vis2[c.i+1][c.j]==0){
vis2[c.i+1][c.j]=c.t+1;
Q.push(cor(c.i+1,c.j,c.t+1,2));
}
if(c.j>0&&vis2[c.i][c.j-1]==0){
vis2[c.i][c.j-1]=c.t+1;
Q.push(cor(c.i,c.j-1,c.t+1,2));
}
if(c.j+1<m&&vis2[c.i][c.j+1]==0){
vis2[c.i][c.j+1]=c.t+1;
Q.push(cor(c.i,c.j+1,c.t+1,2));
}
}
}
/*for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(vis1[i][j]==0)
vis1[i][j]=-1;
if(vis1[i][j]==0)
vis1[i][j]=-2;
}
}*/
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
//printf("% 3d",vis1[i][j]);
if(g[i][j]=='@'&&vis1[i][j]>0&&vis2[i][j]>0&&mind>vis1[i][j]+vis2[i][j]){
mind=(vis1[i][j]+vis2[i][j]);
}
}
// printf("\n");
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
for(int i=0;i<n;i++){
scanf("%s",g[i]);
}
memset(vis1,0,sizeof(vis1));
memset(vis2,0,sizeof(vis2));
mind=0x3f3f3f3f;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(g[i][j]=='Y'){
yi=i,yj=j;
}
else if(g[i][j]=='M'){
mi=i,mj=j;
}
else if(g[i][j]=='#'){
vis1[i][j]=-1;
vis2[i][j]=-1;
}
}
}
bfs();
printf("%d\n",11*mind);
}
}
总结
1.dfs进入时标记状态,退出时清除标记
2.bfs等需要保持步数、转移方向等的时候最好定义结构体
3.我好像喜欢把bfs的入队写成enqueue()函数,可能跟我喜欢写dfs有关。
4.初始化、清空是个好习惯。
本文深入探讨了深度优先搜索(DFS)和广度优先搜索(BFS)在解决复杂问题中的应用,包括棋盘问题、迷宫求解、油井探测等场景,提供了详细的代码实现和技巧分享。
410

被折叠的 条评论
为什么被折叠?



