没想到这么久没写博客了!之前蓝桥杯省赛加校赛一直没空补博客内容....(打水漂真的挺好玩的)
最近开始补kuangbin专题,虽然是简单搜索。。。但是做着一点都不简单= =
A - 棋盘问题
第一题,大意是说给个棋盘(矩形),有可放棋子的地方和不可放棋子的地方,给定需要放的棋子数,且一行或一列只允许有一个棋子,求一共的方案数。Ps:我只知道这数据特别小....写个dfs就过去了,不过我的dfs真的弱啊。。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int map[8+5][8+5];
int vis[8+5];
int k,n; //k是放的棋子数,n是棋盘大小
int cnt;
void dfs(int x,int num)
{
if(num==k)
{
cnt++;
return ;
}
if(x>n) return ;
for(int i=1;i<=n;i++)
{
if(vis[i]==0&&map[x][i]==1)
{
vis[i]=1;
dfs(x+1,num+1);
vis[i]=0;
}
}
dfs(x+1,num);
}
int main()
{
char ch;
while(scanf("%d%d",&n,&k)&&n!=-1&&k!=-1) //限制条件
{
if(n==-1&&k==-1)
break;
memset(map,0,sizeof(map));
memset(vis,0,sizeof(vis));
cnt=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
cin>>ch;
if(ch=='#')
map[i][j]=1;
else
map[i][j]=0;
}
/*for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cout<<map[i][j]<<" ";
}
cout<<endl;
}
cout<<endl;*/
dfs(1,0);
printf("%d\n",cnt);
}
return 0;
}
B - Dungeon Master
题目大意:一个类似塔的迷宫,每一个格子可以跳上一层或者落下一层,以及上下左右,找出最少时间。
这题让我注意到了bfs和dfs分别该怎么用,对于迷宫,一般dfs都是求可不可以到达,bfs求的是到达的步数吧(慢慢从起点上下左右的走)。(可能有错,个人理解)
BFS能够求得最短路径,因为BFS每进行一次相当于当前的路径长度。对于一个N*N矩阵,BFS最多运行n*n次。
深度优先搜索优先寻找离起点最远的顶点,广度优先搜索最先找最近的顶点 ,
深度优先找到的必然是一个连通分量(因为走到死胡同为止)。-----引用一位大佬的话...
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
int l,r,c;
char map[30+5][30+5][30+5]; //x,y,z
int vis[30+5][30+5][30+5];
int s[6][3]={{0,0,-1},{0,0,1},{0,-1,0},{0,1,0},{1,0,0},{-1,0,0}}; //上下左右前后x,y,z
struct node
{
int x,y,z;
int step;
};
int sx,sy,sz; //记录起点位置
void init() //初始化
{
memset(vis,0,sizeof(vis));
memset(map,0,sizeof(map));
}
void pin(queue<node> q) //打印队列。。。我测试用
{
node a;
cout<<"now"<<endl;
while(!q.empty())
{
a=q.front(); //取队头
cout<<a.x<<" "<<a.y<<" "<<a.z<<endl;
q.pop();
}
cout<<"end"<<endl;
}
void BFS() //就。。。模版bfs
{
queue<node> q;
node a,stem;
a.x=sx;
a.y=sy;
a.z=sz;
a.step=0;
q.push(a);
vis[sx][sy][sz]=1;
while(!q.empty())
{
//pin(q);
a=q.front(); //取队头
if(map[a.x][a.y][a.z]=='E')
{
cout<<"Escaped in "<<a.step<<" minute(s)."<<endl;
return ;
}
q.pop(); //删队头
for(int i=0;i<6;i++)
{
if(a.x+s[i][0]>r||a.x+s[i][0]<1||a.y+s[i][1]>c||a.y+s[i][1]<1||a.z+s[i][2]>l||a.z+s[i][2]<1)
continue; //边界判断!!!
if(!vis[a.x+s[i][0]][a.y+s[i][1]][a.z+s[i][2]]&&map[a.x+s[i][0]][a.y+s[i][1]][a.z+s[i][2]]!='#') //若未访问且不是障碍
{
stem.x=a.x+s[i][0];
stem.y=a.y+s[i][1];
stem.z=a.z+s[i][2];
stem.step=a.step+1;
vis[a.x+s[i][0]][a.y+s[i][1]][a.z+s[i][2]]=1;
q.push(stem);
}
}
}
cout<<"Trapped!"<<endl;
}
int main()
{
while(cin>>l>>r>>c&&l+r+c!=0)
{
init();
for(int k=1;k<=l;k++)
{
for(int i=1;i<=r;i++)
{
for(int j=1;j<=c;j++)
{
cin>>map[i][j][k];
if(map[i][j][k]=='S')
sx=i,sy=j,sz=k;
}
}
}
BFS();
}
}
题目大意:一个牛在一个直线上,而放牛人可以走三种①x+1②x-1③x*2,问最短走到的步数(这题在我最开始接触acm的时候做到过。。。觉得这题这恶心,现在看起来好简单啊= =)不过我做的时候还是很慢。。
#include<cstdio>
#include<string.h>
#include<queue>
#include<iostream>
using namespace std;
bool vis[100000*2+5]; //数组只能开到1e11
int c[100000*2+5];
int wz[100000*2+5];
int n,k;
int ans;
int now,to; //now代表前一个集合数,to是计算根据前一个集合入队的新集合数
/*void bfs(int v) //5 17为例 {5}{6,4,10}{7,12,3,8,9,11,20}....一个集合入队为加一分钟时间(我的弱算法,太长了!)
{
queue<int> q; //创建队列
q.push(v); //将起点入队,作为队头
vis[v]=true; //入队的标记
int num=1,to;
while(!q.empty()) //遍历队列q
{
ans++;
for(int i=1;i<=num;i++)
{
c[i]=q.front(); //取队头
q.pop();
if(c[i]==k)
{
cout<<ans<<endl;
return ;
}
}
to=0;
for(int i=1;i<=num;i++)
{
if(vis[c[i]+1]==false&&c[i]!=100000) //若未访问则入队
{
to++;
vis[c[i]+1]=true;
q.push(c[i]+1);
}
if(vis[c[i]-1]==false&&c[i]!=0) //若未访问则入队
{
vis[c[i]-1]=true;
q.push(c[i]-1);
to++;
}
if(vis[2*c[i]]==false&&c[i]<=50000) //若未访问则入队
{
vis[2*c[i]]=true;
q.push(2*c[i]);
to++;
}
}
num=to;
}
}*/
void bfs_better(int v) //wz【】数组的下标为位置,值为时间
{
queue<int> q; //创建队列
q.push(v); //将起点入队,作为队头
wz[v]=0; //入队的标记
while(!q.empty()) //遍历队列q
{
int x=q.front(); //取队头
q.pop();
if(x==k)
{
cout<<wz[k]<<endl;
return;
}
if(wz[x+1]==0&&x!=100000) //若未访问则入队
{
wz[x+1]=wz[x]+1;
q.push(x+1);
}
if(wz[x-1]==0&&x!=0) //若未访问则入队
{
wz[x-1]=wz[x]+1;
q.push(x-1);
}
if(wz[2*x]==0&&x<=50000) //若未访问则入队
{
wz[2*x]=wz[x]+1;
q.push(2*x);
}
}
}
int main()
{
while(cin>>n>>k)
{
ans=-1;
bfs_better(n);
}
return 0;
}
//数组只能开到1e11
int c[100000*2+5];
int wz[100000*2+5];
int n,k;
int ans;
int now,to; //now代表前一个集合数,to是计算根据前一个集合入队的新集合数
/*void bfs(int v) //5 17为例 {5}{6,4,10}{7,12,3,8,9,11,20}....一个集合入队为加一分钟时间(我的弱算法,太长了!)
{
queue<int> q; //创建队列
q.push(v); //将起点入队,作为队头
vis[v]=true; //入队的标记
int num=1,to;
while(!q.empty()) //遍历队列q
{
ans++;
for(int i=1;i<=num;i++)
{
c[i]=q.front(); //取队头
q.pop();
if(c[i]==k)
{
cout<<ans<<endl;
return ;
}
}
to=0;
for(int i=1;i<=num;i++)
{
if(vis[c[i]+1]==false&&c[i]!=100000) //若未访问则入队
{
to++;
vis[c[i]+1]=true;
q.push(c[i]+1);
}
if(vis[c[i]-1]==false&&c[i]!=0) //若未访问则入队
{
vis[c[i]-1]=true;
q.push(c[i]-1);
to++;
}
if(vis[2*c[i]]==false&&c[i]<=50000) //若未访问则入队
{
vis[2*c[i]]=true;
q.push(2*c[i]);
to++;
}
}
num=to;
}
}*/
void bfs_better(int v) //wz【】数组的下标为位置,值为时间
{
queue<int> q; //创建队列
q.push(v); //将起点入队,作为队头
wz[v]=0; //入队的标记
while(!q.empty()) //遍历队列q
{
int x=q.front(); //取队头
q.pop();
if(x==k)
{
cout<<wz[k]<<endl;
return;
}
if(wz[x+1]==0&&x!=100000) //若未访问则入队
{
wz[x+1]=wz[x]+1;
q.push(x+1);
}
if(wz[x-1]==0&&x!=0) //若未访问则入队
{
wz[x-1]=wz[x]+1;
q.push(x-1);
}
if(wz[2*x]==0&&x<=50000) //若未访问则入队
{
wz[2*x]=wz[x]+1;
q.push(2*x);
}
}
}
int main()
{
while(cin>>n>>k)
{
ans=-1;
bfs_better(n);
}
return 0;
}
D - Fliptile
题目大意:奶牛要翻砖块,黑色和白色,需要全白。给了一个矩阵,1代表黑色,0代表白色,问最少翻转次数,并且用矩阵表示出来。。这个题面也是没谁了。(这题感觉和POJ1753很像。。不过做法都不一样,明早醒来再看看具体为什么)
做法:枚举第一行的情况(得到了一种枚举二进制的方法),然后从第二行开始,因为每个棋子都看作翻转全靠下面那块地方,然后每个都这样试完到最后看一看最后一行是否全白即可。
#include<cstdio> //自写
#include<iostream>
#include<cstring>
using namespace std;
int map[15+5][15+5]; //初始化棋盘
int cal[15+5][15+5]; //翻转次数的棋盘
int ans[15+5][15+5]; //最后存储的棋盘
int n,m;
int minnum=15*15+5,num; //minnum为最少翻转次数,num为翻转次数
int p[5][2]={{0,0},{-1,0},{0,1},{1,0},{0,-1}};//原,上,右,下,左
bool check(int x,int y) //白色返回true
{
int a=map[x][y];
for(int i=0;i<5;i++)
{
a+=cal[x+p[i][0]][y+p[i][1]];
}
if(a%2==0)
return true;
else return false;
}
void dfs(int x)
{
num=x;
for(int i=2;i<=n;i++)//从第二行开始往下检查,若当前检查的上一块是黑的则需要翻转
{
for(int j=1;j<=m;j++)
if(check(i-1,j)==false)
{
cal[i][j]=1;
num++;
}
}
for(int i=1;i<=m;i++)
{
if(check(n,i)==false) //有黑色 则不行
return ;
}
if(num<minnum) //如果翻转次数更少则把翻转矩阵复制给ans
{
minnum=num;
memcpy(ans,cal,sizeof(cal));
}
}
int main()
{
while(cin>>n>>m)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
cin>>map[i][j];
}
int end=1<<m,x;
for(int i=0;i<end;i++) //枚举第一行的情况,0~2的m次方
{
x=0;
memset(cal,0,sizeof(cal));
for(int j=0;j<m;j++)
{
cal[1][m-j]=(i>>j)&1;
if(cal[1][m-j])
x++;
}
dfs(x);
}
if(minnum==15*15+5)
cout<<"IMPOSSIBLE"<<endl;
else
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(j!=m)
cout<<ans[i][j]<<" ";
else
{
cout<<ans[i][j];
cout<<endl;
}
}
}
}
return 0;
}
E - Find The Multiple
题目大意:给一个数n,输出一个n的倍数,且用1010表示(但是还是十进制,并不是二进制)
最开始没思路。。。忍不住看了网上的发现也太简单了。。以后决定忍住不看答案先想想.
值得一提的这里需要unsigned long long
llu是1e19,而ll是1e18,int是1e9
#include<iostream>
using namespace std;
bool flag;
void dfs(unsigned long long num,int n,int k) //num是当前数,n是输入的数,k是位数
{
if(flag)
return;
if(num%n==0)
{
printf("%llu\n",num);
flag=true;
return;
}
if(k==19)
return;
dfs(num*10,n,k+1);
dfs(num*10+1,n,k+1);
}
int main()
{
int n;
while(cin>>n,n)
{
flag=false;
dfs(1,n,0);
}
return 0;
}
题目大意:
按如图所示的方式将两个牌堆合在一起,求合几次能得到与题目要求相同的牌堆,若永远无法得到,输出-1
思路:模拟,若模拟次数大于2*C,则永远得不到要求的牌堆
直接给代码模拟
#include<iostream>
#include<string.h>
using namespace std;
string a,b,ans,temp1,temp2,fir;
int main()
{
int n,m,flag,k;
cin>>n;
for(int i=1;i<=n;i++)
{
flag=0;
k=0;
cin>>m;
cin>>a>>b>>ans;
fir=a+b;
temp2=a+b;
temp1=a+b;
while(1)
{
k++;
for(int j=0;j<m;j++)
{
temp2[2*j+1]=temp1[j];
}
for(int j=m;j<2*m;j++)
{
temp2[2*j-2*m]=temp1[j];
}
temp1=temp2;
if(temp1==ans)
{
flag=1;
break;
}
if(k>2*m||temp1==fir)
break;
}
if(flag)
cout<<i<<" "<<k<<endl;
else
cout<<i<<" "<<"-1"<<endl;
}
}
int n,m,flag,k;
cin>>n;
for(int i=1;i<=n;i++)
{
flag=0;
k=0;
cin>>m;
cin>>a>>b>>ans;
fir=a+b;
temp2=a+b;
temp1=a+b;
while(1)
{
k++;
for(int j=0;j<m;j++)
{
temp2[2*j+1]=temp1[j];
}
for(int j=m;j<2*m;j++)
{
temp2[2*j-2*m]=temp1[j];
}
temp1=temp2;
if(temp1==ans)
{
flag=1;
break;
}
if(k>2*m||temp1==fir)
break;
}
if(flag)
cout<<i<<" "<<k<<endl;
else
cout<<i<<" "<<"-1"<<endl;
}
}
H - Pots
题目大意:输入两个容器的容量A,B,一开始让两个容器为空,然后给你对这两个容器的6种操作, 让你用这6种操作最终使得A或B容器里的水最终达到C,让你输出需要倒水的次数,以及从一开始到后来得到结果的路径。(要求C的大小在A和B之间)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 105;
const double eps = 1e-7;
bool vis[maxn][maxn];
const int dir[4][2]= {1, 0, 0, 1, -1, 0, 0, -1};
char map[maxn][maxn];
int a, b, k;
struct node
{
int vola, volb, step;
char str[maxn][maxn];
};
bool bfs()
{
memset(vis, false, sizeof(vis));
queue<node> que;
node p, q;
p.vola = 0, p.volb = 0, p.step = 0;
que.push(p);
vis[0][0] = 1;
///vis[p.vola][p.volb] = true;
while(!que.empty())
{
p = que.front();
que.pop();
if(p.vola==k || p.volb == k)
{
cout<<p.step<<endl;
for(int i=1; i<=p.step; i++)
///cout<<p.str[i]<<endl;
printf("%s\n",p.str[i]);
return true;
}
///倒满 a
if(p.vola == 0)
{
q = p;
q.vola = a;
q.step++;
strcpy(q.str[q.step], "FILL(1)");
if(!vis[q.vola][q.volb])
{
vis[q.vola][q.volb] = true;
que.push(q);
}
}
///把 a 中的水倒出来
else if(p.vola <= a)
{
q = p;
q.vola = 0;
q.step++;
strcpy(q.str[q.step], "DROP(1)");
if(!vis[q.vola][q.volb])
{
vis[q.vola][q.volb] = true;
que.push(q);
}
///a -> b
if(p.volb < b)
{
q = p;
if(q.volb + q.vola <= b)
{
q.volb += q.vola;
q.vola = 0;
}
else
{
q.vola = (q.vola+q.volb)-b;
q.volb = b;
}
q.step++;
strcpy(q.str[q.step], "POUR(1,2)");
if(!vis[q.vola][q.volb])
{
vis[q.vola][q.volb] = true;
que.push(q);
}
}
}
///把 b 倒满
if(p.volb == 0)
{
q = p;
q.volb = b;
q.step++;
strcpy(q.str[q.step], "FILL(2)");
if(!vis[q.vola][q.volb])
{
vis[q.vola][q.volb] = true;
que.push(q);
}
}
///把 b 中的水倒出来
else if(p.volb <= b)
{
q = p;
q.volb = 0;
q.step++;
strcpy(q.str[q.step],"DROP(2)");
if(!vis[q.vola][q.volb])
{
vis[q.vola][q.volb] = true;
que.push(q);
}
if(p.vola < a)
{
q = p;
if(q.vola + q.volb <= a)
{
q.vola += q.volb;
q.volb = 0;
}
else
{
q.volb = (q.vola+q.volb)-a;
q.vola = a;
}
q.step++;
strcpy(q.str[q.step], "POUR(2,1)");
if(!vis[q.vola][q.volb])
{
vis[q.vola][q.volb] = true;
que.push(q);
}
}
}
}
return false;
}
int main()
{
while(cin>>a>>b>>k)
{
bool ok = bfs();
if(!ok)
puts("impossible");
}
return 0;
}
I - Fire Game
题目大意:给一片n*m(n<10,m<=10)草地的图,‘.’代表土地,‘#’代表草丛,最开始可以点燃两个草丛,点燃的草没过一秒,火势便会往上下左右蔓延,问找出一种点燃初始草,使得时间最少将所有草丛烧完,若没办法烧完则输出-1.
思路:因为n和m都很小,我们可以枚举任意两个草进行BFS,找出时间最少的。
#include<iostream>
#include<queue>
#include<string.h>
const int maxn=1e6;
using namespace std;
int n,m;
int ans;
char map[10+5][10+5];
int mp[10+5][10+5];
int st[4][2]={{-1,0},{1,0},{0,1},{0,-1}}; //上,下,右,左
struct node
{
int x,y;
int t;
};
bool check() //检查是不是所有草丛都烧完了
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
if(mp[i][j]==0&&map[i][j]=='#')
return false;
}
return true;
}
void bfs(node s1,node s2) //bfs
{
node n1,temp;
int tt=0; //记录进行到第几秒了
queue<node> q;
q.push(s1);
q.push(s2);
mp[s1.x][s1.y]=1;
mp[s2.x][s2.y]=1;
while(!q.empty())
{
n1=q.front();
q.pop();
int x1=n1.x;
int y1=n1.y;
int t1=n1.t;
if(check())
{
if(tt<ans) //如果当前时间小于最终答案
{
ans=tt;
}
return;
}
for(int i=0;i<4;i++) //每个燃烧的草的上下左右入队
{
temp.x=x1+st[i][0];
temp.y=y1+st[i][1];
temp.t=t1+1;
if(t1+1>=tt)
tt=t1+1;
if(temp.x>=1&&temp.x<=n&&temp.y>=1&&temp.y<=m&&map[temp.x][temp.y]=='#'&&!mp[temp.x][temp.y])
{
q.push(temp);
mp[temp.x][temp.y]=1;
}
}
}
return ;
}
int main()
{
node s1,s2;
int c;
cin>>c;
int num;
for(int i1=1;i1<=c;i1++)
{
num=0;
cin>>n>>m;
for(int i=1;i<=n;i++) //输入草地
{
for(int j=1;j<=m;j++)
{
cin>>map[i][j];
if(map[i][j]=='#')
num++;
}
}
ans=maxn;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(map[i][j]=='#')
{
for(int k=i;k<=n;k++)
{
for(int l=1;l<=m;l++)
{
if(map[k][l]=='#')
{
if(k==i&&l<=j)
{
continue;
}
else
{
s1.x=i,s1.y=j,s1.t=0;
s2.x=k,s2.y=l,s2.t=0;
memset(mp,0,sizeof(mp));
bfs(s1,s2);
}
}
}
}
}
}
}
cout<<"Case "<<i1<<": ";
if(num==1||num==2)
cout<<"0"<<endl;
else if(ans==maxn)
cout<<"-1"<<endl;
else
cout<<ans<<endl;
}
return 0;
}
J - Fire!
题目大意:给一个地图,一个地方是火一个地方是人,火会往四个方向蔓延,看人能否找到一条最短路且不被火烧的的情况先逃生到地图外。
思路:直接先把F(火)bfs,记录火到每一格的时间,然后人在bfs看看能不能在火未到的情况下逃生。双端BFS
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
int n,m;
char map[1000+5][1000+5];
int mp[1000+5][1000+5]; //火势蔓延的时间
int vis_man [1000+5][1000+5];
int st[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
struct node
{
int x,y,step;
};
queue<node> q;
void clear_q()//用来清除队列中的数据
{
while(!q.empty())
q.pop();
}
void bfs1(node f) //火势蔓延到每格的时间
{
//cout<<"text1"<<endl;
node t,temp;
t.step=f.step;
t.x=f.x;
t.y=f.y;
int x,y,s;
q.push(t);
while(!q.empty())
{
//cout<<"text2"<<endl;
t=q.front();
q.pop();
x=t.x;
y=t.y;
s=t.step;
for(int i=0;i<4;i++) //火的四个方向
{
temp.x=x+st[i][1];
temp.y=y+st[i][0];
temp.step=s+1;
if(map[temp.x][temp.y]!='#'&&map[temp.x][temp.y]!='F'&&mp[temp.x][temp.y]==0&&temp.x>=1&&temp.x<=n&&temp.y>=1&&temp.y<=m) //如果不是墙且等于0,即火还未蔓延到
{
cout<<temp.x<<" "<<temp.y<<endl;
mp[temp.x][temp.y]=s+1;
q.push(temp);
}
}
}
return;
}
void bfs2(node j)
{
clear_q();
node t,temp;
int x,y,s;
q.push(j);
vis_man[j.x][j.y]=1;
while(!q.empty())
{
t=q.front();
q.pop();
x=t.x;
y=t.y;
s=t.step;
if(x==n||x==1||y==1||y==m)
{
cout<<s+1<<endl;
return ;
}
for(int i=0;i<4;i++) //J的四个方向
{
temp.x=x+st[i][1];
temp.y=y+st[i][0];
temp.step=s+1;
if(map[temp.x][temp.y]=='.'&&temp.step<mp[temp.x][temp.y]&&temp.x>=1&&temp.x<=n&&temp.y>=1&&temp.y<=m&&vis_man[temp.x][temp.y]==0) //如果是.且时间小于,即火还未蔓延到
{
vis_man[temp.x][temp.y]=1;
q.push(temp);
}
}
}
cout<<"IMPOSSIBLE"<<endl;
return;
}
int main()
{
int t;
node j1,f1;
cin>>t;
while(t--)
{
memset(mp,0,sizeof(mp));
memset(vis_man,0,sizeof(vis_man));
clear_q();
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>map[i][j];
if(map[i][j]=='J')
{
j1.x=i;
j1.y=j;
j1.step=0;
}
if(map[i][j]=='F')
{
f1.x=i;
f1.y=j;
f1.step=0;
q.push(f1);
}
}
}
bfs1(f1);
/* for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cout<<mp[i][j]<<" ";
}
cout<<endl;
}*/
bfs2(j1);
}
return 0;
}
K - 迷宫问题
题目大意:给一个矩阵,0代表路,1代表障碍,找出一条最短路,输出这条路
思路:基础bfs,pre数组记录每个点的前一个点,用来记录路径
#include<iostream>
#include<queue>
using namespace std;
int map[5+5][5+5];
int mp[5+5][5+5];
int st[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
int road[25+5][2];
int pre[10][10];
struct node
{
int x,y;
int prex,prey;
};
void bfs()
{
node star;
star.x=0;
star.y=0;
queue<node>q;
q.push(star);
while(!q.empty())
{
node fi=q.front();
q.pop();
int x=fi.x;
int y=fi.y;
if(x==4&&y==4)
{
int i=1;
while(x*10+y!=0)
{
road[i][0]=x;
road[i][1]=y;
x=pre[road[i][0]][road[i][1]]/10;
y=pre[road[i][0]][road[i][1]]%10;
i++;
}
road[i][0]=x;
road[i][1]=y;
for(int k=i;k>=1;k--)
{
cout<<"("<<road[k][0]<<", "<<road[k][1]<<")"<<endl;
}
break;
}
node t;
for(int i=0;i<4;i++)
{
t.x=x+st[i][0];
t.y=y+st[i][1];
if(t.x>=0&&t.x<5&&t.y>=0&&t.y<5&&mp[t.x][t.y]==0&&map[t.x][t.y]==0)
{
pre[t.x][t.y]=x*10+y;
mp[t.x][t.y]=1;
q.push(t);
}
}
}
}
void dfs(int x,int y)
{
}
int main()
{
mp[1][1]=1;
for(int i=0;i<5;i++)
for(int j=0;j<5;j++)
{
cin>>map[i][j];
}
bfs();
return 0;
}
L - Oil Deposits
题目大意:给一个地图#代表路,@代表油,如果油的九宫格还有其他油,这些油属于同一种油,问一一共有几种油
思路:遇到@就BFS,标记与@相同的油,看看一共进行了几次bfs,一次则代表有一种油
#include<iostream>
#include<queue>
#include<string.h>
using namespace std;
int vis[100+5][100+5];
char map[100+5][100+5];
int ans,n,m;
struct node
{
int x,y;
};
int st[8][2]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
void bfs(int i,int j)
{
ans++;
queue<node> q;
node t,temp;
int a,b;
t.x=i;
t.y=j;
vis[i][j]=1;
q.push(t);
while(!q.empty())
{
t=q.front();
a=t.x;
b=t.y;
q.pop();
for(int i=0;i<8;i++)
{
temp.x=a+st[i][0];
temp.y=b+st[i][1];
if(temp.x<=n&&temp.x>=1&&temp.y<=m&&temp.y>=1&&vis[temp.x][temp.y]==0&&map[temp.x][temp.y]=='@')
{
vis[temp.x][temp.y]=1;
q.push(temp);
}
}
}
return ;
}
int main()
{
while(cin>>n>>m&&(n+m)!=0)
{
memset(vis,0,sizeof(vis));
memset(map,0,sizeof(map));
ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>map[i][j];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(map[i][j]=='@'&&vis[i][j]==0)
bfs(i,j);
}
cout<<ans<<endl;
}
}
M - 非常可乐
题意:有一瓶可乐,两个空瓶子,问最少几次可以倒成2瓶一样的
思路,bfs(1->2,1->3,2->1,2->3,3->1,3->2)直到有两个瓶子是一样的,坑点是。。可乐瓶居然也可以当杯子(可能是我脑残= =)
#include<iostream>
#include<queue>
#include<string.h>
using namespace std;
int s,n,m;
int vis[100+5][100+5];
int pre[100+5][100+5];
struct node
{
int ls,ln,lm,step; //,s,n,m代表是三个属性,ln代表已经倒的,lm代表已经倒的
};
void bfs()
{
node t,temp;
queue<node> q;
t.ls=s;
t.ln=0;
t.lm=0;
t.step=0;
vis[0][0]=1;
q.push(t);
int i=0;
int ls,ln,lm,step;
while(!q.empty())
{
temp=q.front();
q.pop();
ls=temp.ls;
ln=temp.ln;
lm=temp.lm;
step=temp.step;
if((ls==s/2&&lm==s/2)||(ls==s/2&&ln==s/2)||(ln==s/2&&lm==s/2))
{
/*for(int k=0;k<=5;k++)
{
for(int l=0;l<=5;l++)
{
cout<<vis[k][l]<<" ";
}
cout<<endl;
}
cout<<"pre"<<endl;
for(int k=0;k<=5;k++)
{
for(int l=0;l<=5;l++)
{
cout<<pre[k][l]<<" ";
}
cout<<endl;
}*/
cout<<step<<endl;//<<" "<<ls<<" "<<ln <<" "<<lm<<endl;
return ;
}
if(ls>0)//将1倒给其它两瓶
{
if(ln<n) //1->2
{
if((ls+ln)<=n)
{
t.ls=0;
t.ln=ls+ln;
t.step=step+1;
t.lm=lm;
if(vis[t.ln][t.lm]==0)
{
vis[t.ln][t.lm]=1;
pre[t.ln][t.lm]=ln*10+lm;
q.push(t);
}
}
else
{
t.ls=ls-(n-ln);
t.ln=n;
t.step=step+1;
t.lm=lm;
if(vis[t.ln][t.lm]==0)
{
vis[t.ln][t.lm]=1;
pre[t.ln][t.lm]=ln*10+lm;
q.push(t);
}
}
}
if(lm<m) //1->3
{
if((ls+lm)<=m)
{
t.ls=0;
t.lm=ls+lm;
t.step=step+1;
t.ln=ln;
if(vis[t.ln][t.lm]==0)
{
vis[t.ln][t.lm]=1;
pre[t.ln][t.lm]=ln*10+lm;
q.push(t);
}
}
else
{
t.ls=ls-(m-lm);
t.lm=m;
t.step=step+1;
t.ln=ln;
if(vis[t.ln][t.lm]==0)
{
vis[t.ln][t.lm]=1;
pre[t.ln][t.lm]=ln*10+lm;
q.push(t);
}
}
}
}
if(ln>0)
{
if(ls<s) //2->1
{
if((ls+ln)<=s)
{
t.ln=0;
t.ls=ls+ln;
t.step=step+1;
t.lm=lm;
if(vis[t.ln][t.lm]==0)
{
vis[t.ln][t.lm]=1;
pre[t.ln][t.lm]=ln*10+lm;
q.push(t);
}
}
else
{
t.ln=ln-(s-ls);
t.ls=s;
t.step=step+1;
t.lm=lm;
if(vis[t.ln][t.lm]==0)
{
vis[t.ln][t.lm]=1;
pre[t.ln][t.lm]=ln*10+lm;
q.push(t);
}
}
}
if(lm<m) //2->3
{
if((ln+lm)<=m)
{
t.ln=0;
t.lm=ln+lm;
t.step=step+1;
t.ls=ls;
if(vis[t.ln][t.lm]==0)
{
vis[t.ln][t.lm]=1;
pre[t.ln][t.lm]=ln*10+lm;
q.push(t);
}
}
else
{
t.ln=ln-(m-lm);
t.lm=m;
t.step=step+1;
t.ls=ls;
if(vis[t.ln][t.lm]==0)
{
vis[t.ln][t.lm]=1;
pre[t.ln][t.lm]=ln*10+lm;
q.push(t);
}
}
}
}
if(lm>0)
{
if(ls<s) //3->1
{
if((ls+lm)<=s)
{
t.lm=0;
t.ls=ls+lm;
t.step=step+1;
t.ln=ln;
if(vis[t.ln][t.lm]==0)
{
vis[t.ln][t.lm]=1;
pre[t.ln][t.lm]=ln*10+lm;
q.push(t);
}
}
else
{
t.lm=lm-(s-ls);
t.ls=s;
t.step=step+1;
t.ln=ln;
if(vis[t.ln][t.lm]==0)
{
vis[t.ln][t.lm]=1;
pre[t.ln][t.lm]=ln*10+lm;
q.push(t);
}
}
}
if(ln<n) //3->2
{
if((ln+lm)<=n)
{
t.lm=0;
t.ln=ln+lm;
t.step=step+1;
t.ls=ls;
if(vis[t.ln][t.lm]==0)
{
vis[t.ln][t.lm]=1;
pre[t.ln][t.lm]=ln*10+lm;
q.push(t);
}
}
else
{
t.ln=n;
t.lm=lm-(n-ln);
t.step=step+1;
t.ls=ls;
if(vis[t.ln][t.lm]==0)
{
vis[t.ln][t.lm]=1;
pre[t.ln][t.lm]=ln*10+lm;
q.push(t);
}
}
}
}
}
/*for(int k=0;k<=5;k++)
{
for(int l=0;l<=5;l++)
{
cout<<vis[k][l]<<" ";
}
cout<<endl;
}
cout<<"pre"<<endl;
for(int k=0;k<=5;k++)
{
for(int l=0;l<=5;l++)
{
cout<<pre[k][l]<<" ";
}
cout<<endl;
}*/
cout<<"NO"<<endl;
return ;
}
int main()
{
while(cin>>s>>n>>m&&m+n+s!=0)
{
memset(pre,-1,sizeof(pre));
memset(vis,0,sizeof(vis));
if(s%2==0)
bfs();
else
cout<<"NO"<<endl;
}
return 0;
}
N - Find a way
题目大意:给一个地图,有两个人Y和M,'@'代表KFC,'#'代表障碍,‘.’代表路,问找一个对于两个人来说都是最短的KFC
思路:先对Y做BFS记录所有Y到KFC的时间记录,然后对M做BFS
#include<iostream>
#include<queue>
#include<string.h>
using namespace std;
struct node
{
int x,y,step;
};
int st[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
int n,m;
int vis[200+5][200+5];
int y1,y2,x1,x2;
char map[200+5][200+5];
int time[200+5][200+5];
int mint;
void bfs()
{
queue<node>q;
node f,t;
int x,y,s;
f.x=x1;
f.y=y1;
f.step=0;
time[x1][y1]=0;
q.push(f);
while(!q.empty())
{
f=q.front();
q.pop();
x=f.x;
y=f.y;
s=f.step;
for(int i=0;i<4;i++)
{
t.x=x+st[i][0];
t.y=y+st[i][1];
t.step=s+1;
if(time[t.x][t.y]==-1&&t.x>=1&&t.x<=n&&t.y>=1&&t.y<=m&&map[t.x][t.y]!='#')
{
time[t.x][t.y]=t.step;
q.push(t);
}
}
}
return;
}
void bfsm()
{
queue<node>q;
node f,t;
int x,y,s;
f.x=x2;
f.y=y2;
f.step=0;
vis[x2][y2]=0;
q.push(f);
while(!q.empty())
{
f=q.front();
q.pop();
x=f.x;
y=f.y;
s=f.step;
if(map[x][y]=='@'&&time[x][y]>=0)
{
if((time[x][y]*11+s*11)<mint)
{
mint=time[x][y]*11+s*11;
}
}
for(int i=0;i<4;i++)
{
t.x=x+st[i][0];
t.y=y+st[i][1];
t.step=s+1;
if(time[t.x][t.y]>=0&&t.x>=1&&t.x<=n&&t.y>=1&&t.y<=m&&map[t.x][t.y]!='#'&&vis[t.x][t.y]==0)
{
vis[t.x][t.y]=1;
q.push(t);
}
}
}
cout<<mint<<endl;
return;
}
int main()
{
while(cin>>n>>m)
{
mint=999999*11;
memset(time,-1,sizeof(time));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>map[i][j];
if(map[i][j]=='Y')
{
x1=i,y1=j;
}
if(map[i][j]=='M')
{
x2=i,y2=j;
}
}
bfs();
bfsm();
}
return 0;
}
拖拖拉拉终于把专题一写完了。。后面的专题一定不会再多于一周了!!