今天网络赛又被虐了,哎,还是太菜,还是忘了吧,重要的是努力,是提升,黑暗总会过去的!!!希望一直都有,只要你肯坚持!从现在做起,重拾信心,重拾希望,不要企图一步登天,不要想那些虚无缥缈的未来,脚踏实地,向前进!
现在就把前阵子写的专题一做个总结吧。
bfs:递归实现,所以容易超时爆栈,而且判重、标记要么都在中间,要么都在开头(根据写法类型而定,“先判再走”or"走后再判")【见A题】。回溯恢复要么都在本层,要么都在下一层。【见A题】
如果题目要求最优解,找到目标后,每次还要进行比较取优。
如果题目中,每一步可以任意走的话,可以采用。
bfs:循环实现,不会爆栈。判重、标记要么都在入队前,要么都在出队后。
第一次找到目标后,就是最优解,无需比较取优。
如果题目中,每一步有规定,只能特定地走,可以采用。
可以打印路径,只要用数组模拟队列,并且在节点的结构体中加一个pre就行,路径的第一个节点的pre设为-1,打印时用一个递归函数,终止条件就是pre!=-1。
A题:
题意:
给你一个n*n的棋盘,棋盘上只有'#'位置可以放置棋子,要求放置k个棋子,棋子每一行,每一列只能有一个棋子。
思路:
由于n,k很小,不超过8,直接暴搜就行,看了一下自己的提交记录,发现并不是1A,任何的非1A都可能导致一场比赛的失败,这也暴露了自己对暴搜写法有一定的问题。
先看一下我的AC代码:
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) { return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
int n,k;
char mp[10][10];
int ans;
int vis1[10];
int vis2[10];
void dfs(int now, int cnt){
if(cnt == k){
ans++;
return;
}
for(int i = now; i <= n; ++i){
if(vis1[i]) continue;
for(int j = 1; j <= n; ++j){
if(vis2[j]) continue;
if(mp[i][j] == '#'){
vis1[i] = 1;
vis2[j] = 1;
dfs(i+1,cnt+1);
vis1[i] = 0;
vis2[j] = 0;
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
while(scanf("%d%d",&n,&k) == 2){
getchar();
if(n == -1 && k == -1) break;
fo(i,1,n+1){
fo(j,1,n+1)
scanf("%c",&mp[i][j]);
getchar();
}
ans = 0;
dfs(1,0);
printf("%d\n",ans);
}
return 0;
}
我上面的AC代码就是典型的判断后再走。
再看一下我的失败代码:
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) { return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
int n,k;
char mp[10][10];
int ans;
int vis1[10];
int vis2[10];
void dfs(int now, int cnt){
if(cnt == k){
ans++;
return;
}
if(vis1[now]) return;
for(int i = now; i <= n; ++i){
for(int j = 1; j <= n; ++j){
if(vis2[j]) continue;
if(mp[i][j] == '#'){
vis1[i] = 1;
vis2[j] = 1;
dfs(now+1,cnt+1);
vis1[i] = 0;
vis2[j] = 0;
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
while(scanf("%d%d",&n,&k) == 2){
getchar();
if(n == -1 && k == -1) break;
fo(i,1,n+1){
fo(j,1,n+1)
scanf("%c",&mp[i][j]);
getchar();
}
ans = 0;
dfs(1,0);
printf("%d\n",ans);
}
return 0;
}
不难发现失败代码与ac代码就差别在对vis1数组的判重的位置,这告诉我,既然选择“判断后再走”,就必须严格遵循“先判重,然后走”,不能又在开头再判重。
另外,又参考了一下别人的代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
char a[10][10];
int ans=0;
int n,k;
int visit [10];
void bfs(int cnt,int x,int y)
{
if(cnt==k) {
ans++;
return ;
}
visit[y]=1;
for(int i=x+1;i<n;i++){
for(int j=0;j<n;j++){
if(visit[j]==0&&a[i][j]=='#') {
bfs(cnt+1,i,j);
}
}
}
visit[y]=0;
}
int main()
{
while(~scanf("%d%d",&n,&k)){
if(n==-1&&k==-1) {
break;
}
for(int i=0;i<n;i++) {
scanf("%s",a[i]);
}
int x,y;
ans=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(a[i][j]=='#') {
memset(visit,0,sizeof(visit));
bfs(1,i,j);
}
}
}
printf("%d\n",ans);
}
}
他的代码在恢复状态的写法与我不同(对visit数组),其实两种方法都可以,我的放在里面,就是等它回到原来这一层,再给恢复,而他的代码,则是在进入下一层再标记,然后在回到本层才恢复标记。
B题:
题意:
给一个三维的迷宫,’#‘不能走,’.'表示可以走,'S'表示起点,'E'表示终点,求最短逃离时间,若不能逃离,输出“Trapped!”,否则输出“Escaped in x minute(s).”。
思路:对于每一步行走有限制的题目,一般采用bfs,而每一步可以任意行走的题,例如上一题,可以采用dfs,本次采用bfs,对六个方向进行试探,入队...
代码1(极其冗杂易错的代码):
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) { return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
typedef struct Node{
int x,y,z;
}Node;
typedef struct node{
int step;
Node loc;
}node;
int l,r,c;
char mp[100][100][100];
int vis[100][100][100];
Node start,end;
queue<node> que;
int ans;
void bfs(){
while(!que.empty())
que.pop();
me(vis,0);
ans = 0;
node Begin;
Begin.step = 0;
Begin.loc.x = start.x;
Begin.loc.y = start.y;
Begin.loc.z = start.z;
que.push(Begin);
vis[start.z][start.x][start.y] = 1;
while(!que.empty()){
node now = que.front();
que.pop();
int step = now.step;
int z = now.loc.z; int x = now.loc.x; int y = now.loc.y;
//printf("now: step:%d z:%d x:%d y:%d\n",step,z,x,y);
if(z == end.z && x == end.x && y == end.y){
//printf("success!! step:%d z:%d x:%d y:%d\n",step,z,x,y);
ans = step;
return;
}
//printf("上: vis:%d mp:%c\n",vis[z+1][x][y],mp[z+1][x][y]);
if(z+1 <= l && !vis[z+1][x][y] && mp[z+1][x][y] != '#'){
//printf("上: step:%d z:%d x:%d y:%d\n",step+1,z+1,x,y);
node temp;
temp.step = step+1;
temp.loc.z = z+1; temp.loc.x = x; temp.loc.y = y;
vis[z+1][x][y] = 1;
que.push(temp);
}
//printf("下: vis:%d mp:%c\n",vis[z-1][x][y],mp[z-1][x][y]);
if(z-1 >= 1 && !vis[z-1][x][y] && mp[z-1][x][y] != '#'){
//printf("下: step:%d z:%d x:%d y:%d\n",step+1,z-1,x,y);
node temp;
temp.step = step+1;
temp.loc.z = z-1; temp.loc.x = x; temp.loc.y = y;
vis[z-1][x][y] = 1;
que.push(temp);
}
//printf("右: vis:%d mp:%c\n",vis[z][x+1][y],mp[z][x+1][y]);
if(x+1 <= r && !vis[z][x+1][y] && mp[z][x+1][y] != '#'){
//printf("右: step:%d z:%d x:%d y:%d\n",step+1,z,x+1,y);
node temp;
temp.step = step+1;
temp.loc.z = z; temp.loc.x = x+1; temp.loc.y = y;
vis[z][x+1][y] = 1;
que.push(temp);
}
//printf("左: vis:%d mp:%c\n",vis[z][x-1][y],mp[z][x-1][y]);
if(x-1 >= 1 && !vis[z][x-1][y] && mp[z][x-1][y] != '#'){
//printf("左: step:%d z:%d x:%d y:%d\n",step+1,z,x-1,y);
node temp;
temp.step = step+1;
temp.loc.z = z; temp.loc.x = x-1; temp.loc.y = y;
vis[z][x-1][y] = 1;
que.push(temp);
}
//printf("前: vis:%d mp:%c\n",vis[z][x][y+1],mp[z][x][y+1]);
if(y+1 <= c && !vis[z][x][y+1] && mp[z][x][y+1] != '#'){
//printf("前: step:%d z:%d x:%d y:%d\n",step+1,z,x,y+1);
node temp;
temp.step = step+1;
temp.loc.z = z; temp.loc.x = x; temp.loc.y = y+1;
vis[z][x][y+1] = 1;
que.push(temp);
}
//printf("后: vis:%d mp:%c\n",vis[z][x][y-1],mp[z][x][y-1]);
if(y-1 >= 1 && !vis[z][x][y-1] && mp[z][x][y-1] != '#'){
//printf("后: step:%d z:%d x:%d y:%d\n",step+1,z,x,y-1);
node temp;
temp.step = step+1;
temp.loc.z = z; temp.loc.x = x; temp.loc.y = y-1;
vis[z][x][y-1] = 1;
que.push(temp);
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
Fin;
#endif // ONLINE_JUDGE
while(scanf("%d%d%d",&l,&r,&c) == 3){
//printf("l:%d r:%d c:%d\n",l,r,c);
//getchar();
if(!l && !r && !c) break;
me(mp,0);
int i,j,k;
for(i = 1; i <= l; ++i){
for(j = 1; j <= r; ++j){
scanf("%s",mp[i][j]+1);
for(k = 1; k <= c; ++k){
if(mp[i][j][k] == 'S'){
start.x = j; start.y= k; start.z = i;
}
if(mp[i][j][k] == 'E'){
end.x = j; end.y= k; end.z = i;
}
}
//getchar();
}
//getchar();
}
/*for(int i = 1; i <= l; ++i){
for(int j = 1; j <= r; ++j){
for(int k = 1; k <= c; ++k){
cout << mp[i][j][k];
}
cout << endl;
}
cout << endl;
}
printf("start: x:%d y:%d z:%d\n",start.x, start.y, start.z);
printf("end: x:%d y:%d z:%d\n",end.x, end.y, end.z);*/
ans = 0;
bfs();
if(ans == 0)
cout << "Trapped!" << endl;
else
printf("Escaped in %d minute(s).\n",ans);
}
return 0;
}
其实上面的bfs的代码量可以缩短很多的,首先可以写一个check函数,判断点是否合理,另外,六个方向可以用三个一维数组(1*6)表示。
代码2(简洁代码,其中的六个方向的表示,代码中提供了两种方法,个人喜欢没被注释掉的那种方法):
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) { return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
int l,r,c;
char mp[35][35][35];
int vis[35][35][35];
//int dire[6][3] = {{0,0,1},{0,0,-1},{1,0,0},{-1,0,0},{0,1,0},{0,-1,0}};
int dirx[] = {0,0,1,-1,0,0};
int diry[] = {0,0,0,0,1,-1};
int dirz[] = {1,-1,0,0,0,0};
int stx,sty,stz,edx,edy,edz;
struct node{
int x,y,z;
int step;
};
queue<node> que;
void Init(){
while(!que.empty())
que.pop();
me(vis,0);
}
int check(node temp){
if(!(1 <= temp.z && temp.z <= l)) return 0;
if(!(1 <= temp.x && temp.x <= r)) return 0;
if(!(1 <= temp.y && temp.y <= c)) return 0;
if(vis[temp.x][temp.y][temp.z]) return 0;
if(mp[temp.z][temp.x][temp.y] == '#') return 0;
return 1;
}
int dfs(){
Init();
node startt;
startt.x = stx, startt.y = sty, startt.z = stz; startt.step = 0;
que.push(startt);
vis[stx][sty][stz] = 1;
while(!que.empty()){
node now = que.front();
que.pop();
int x = now.x; int y = now.y; int z = now.z; int step = now.step;
if(x == edx && y == edy && z == edz){
return step;
}
fo(i,0,6){
node nextt = now;
//nextt.x += dire[i][0];
//nextt.y += dire[i][1];
//nextt.z += dire[i][2];
nextt.x += dirx[i]; nextt.y += diry[i]; nextt.z += dirz[i];
nextt.step++;
if(check(nextt)){
que.push(nextt);
vis[nextt.x][nextt.y][nextt.z] = 1;
}
}
}
return 0;
}
int main()
{
#ifndef ONLINE_JUDGE
Fin;
#endif // ONLINE_JUDGE
while(cin >> l >> r >> c){
if(!l && !r && !c) break;
me(mp,0);
fo(i,1,l+1){
fo(j,1,r+1){
scanf("%s",mp[i][j]+1);
fo(k,1,c+1){
if(mp[i][j][k] == 'S'){
stx = j; sty = k; stz = i;
}
if(mp[i][j][k] == 'E'){
edx = j; edy = k; edz = i;
}
}
}
}
int ans = dfs();
if(ans)
printf("Escaped in %d minute(s).\n",ans);
else
printf("Trapped!\n");
}
return 0;
}
C题
题意:
在一个一维空间里,给你一个初始位置,以及一个目标位置,你有三种方式可以走,1是左移一个单位,2是右移一个单位,3是位置扩为两倍,要求位置在[0,1e5]之间。问到达目标位置最少需要多少步?
思路:
限定了每步只可有三种选择,那么选择dfs,再注意一下边界就行。
代码:
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) { return x & (-x); }
const int maxn = 100000 + 100;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
struct Node{
int step,loc;
Node(int a, int b){
step = a;
loc = b;
}
};
int n,k;
int vis[maxn];
queue<Node> que;
int ans;
int check(int loc){
if(!(0 <= loc && loc <= maxn)) return 0;
if(vis[loc]) return 0;
return 1;
}
void bfs(){
Node start(0,n);
if(n == k)
return;
que.push(start);
vis[n] = 1;
while(!que.empty()){
Node now = que.front();
que.pop();
int step = now.step; int loc = now.loc;
//printf("step:%d loc:%d\n",step,loc);
if(loc == k){
ans = step;
return ;
}
if(check(loc-1)){
Node Next(step+1,loc-1);
que.push(Next);
//printf("loc:%d step:%d\n",Next.loc,Next.step);
vis[loc-1] = 1;
}
if(check(loc+1)){
Node Next(step+1,loc+1);
que.push(Next);
vis[loc+1] = 1;
}
if(check(loc*2)){
Node Next(step+1,loc*2);
que.push(Next);
vis[loc*2] = 1;
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
cin >> n >> k;
ans = 0;
bfs();
cout << ans << endl;
return 0;
}
D题:
题意:
给N*M的01矩阵,对每一个位置,可以进行01翻转,翻转的同时,它的上下左右的四个位置也同时进行01翻转。问最少需要多少次翻转,可以使矩阵全0,输出每个位置的翻转次数。
思路:
首先,明确一点,每一个位置翻转2次,将回到原状态,翻转3次,等同于翻转1次,因而每个位置最多翻转1次。
另外,对于这种翻转问题,而且是对周围的格子有影响的翻转,一般并不需要确定全部格子,只需确定一部分格子,剩下的格子在确定好了的格子的影响下,也将被确定。而对于本题,你只要确定第一行的格子,那么第二行也就确定了(第二行的分布方式得需将第一行变为全0,就是说第一行的第i列为1时,相应的第二行的第i列要翻转一次),同理,第二行确定后,第三行受第二行的约束,也将确定......所以只要枚举第一行就行,可以采用dfs,暴力枚举第一行,对于第一行的每一个位置,进行01试探。
代码:
#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 110000 + 5;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
int mp[20][20];
int temp[20][20];
int ans[20][20];
int answer[20][20];
int cnt;
int m,n;
int flag;
void flip(int x, int y){
if(x-1 >= 1)
temp[x-1][y] = !temp[x-1][y];
if(x+1 <= m)
temp[x+1][y] = !temp[x+1][y];
if(y-1 >= 1)
temp[x][y-1] = !temp[x][y-1];
if(y+1 <= n)
temp[x][y+1] = !temp[x][y+1];
temp[x][y] = !temp[x][y];
}
int Count(){
int sum = 0;
fo(i,1,m+1)
fo(j,1,n+1)
if(ans[i][j] == 1)
sum++;
return sum;
}
void Copy(){
fo(i,1,m+1)
fo(j,1,n+1)
answer[i][j] = ans[i][j];
}
int check(){
for(int i = 1; i <= m; ++i){
for(int j = 1;j <= n; ++j)
temp[i][j] = mp[i][j];
}
fo(i,1,m+1){
fo(j,1,n+1){
if(ans[i][j] == 1)
flip(i,j);
}
if(i != m){
fo(j,1,n+1)
ans[i+1][j] = temp[i][j];
}
}
fo(i,1,m+1){
fo(j,1,n+1){
if(temp[i][j] == 1)
return 0;
}
}
return 1;
}
void dfs(int y){
if(y == n){
ans[1][y] = 0;
if(check()){
flag = 1;
int num = Count();
if(num < cnt){
Copy();
cnt = num;
}
return;
}
ans[1][y] = 1;
if(check()){
int num = Count();
flag = 1;
if(num < cnt){
Copy();
cnt = num;
}
}
return;
}
ans[1][y] = 0;
dfs(y+1);
ans[1][y] = 1;
dfs(y+1);
}
int main()
{
#ifndef ONLINE_JUDGE
Fin;
#endif // ONLINE_JUDGE
cin >> m >> n;
fo(i,1,m+1)
fo(j,1,n+1)
cin >> mp[i][j];
me(ans,0);
flag = 0;
cnt = INF;
dfs(1);
if(flag == 0)
cout << "IMPOSSIBLE" << endl;
else{
print2();
}
return 0;
}
E题:
题意:
给你一个数n,要求输出一个n的倍数m,其中m是只有0和1的十进制数。
思路:
这题的n是不超过200,而m不超过100位,也就是10^(100),当时看了就慌了,这个m没法用任何类型来存啊。。太大了啊。。。后来想想,n不超过200,那么相应的m应该也不会达到100位吧,就用long long试试,然后就过了。。。
由于m只有0和1,那么对于m的每一位进行01试探就行。DFS和BFS都行吧。
我用的bfs(双端口bfs),另外,本题是special judge,也就是可能存在多解,输出一个就行,所以输出结果和样例不同也没事。
代码:
#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 110000 + 5;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
queue<ll> que;
ll n;
void bfs(){
while(!que.empty())
que.pop();
que.push(1);
while (!que.empty()) {
ll temp = que.front();
que.pop();
if(temp%n == 0){
cout << temp << endl;
return;
}
que.push(temp*10);
que.push(temp*10+1);
}
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
while(cin >> n){
if(!n) break;
//printf("n:%lld\n",n);
bfs();
}
return 0;
F题:
题意:
有a,b两个质数,要求通过一些转换,使a变为b,每次变换,只能变换一位,而且变换后的数也得是质数,问最少变换几次,可以得到b。a,b都是四位数。
思路:
由于只有四位数,然后每次只能改变一位数,那么采用bfs,可以对每一位的数依次尝试0~9,一共36种尝试,如果改变一位数后是质数,就入队,直到找到b。
注意点:
由于要对每一位进行改变,所以采用字符数组来存数字,方便对每一位进行操作,然后还得把字符数组表示的数字转化为数字,来判断是否是质数。所以要写一个字符数组的函数:
int chartonum(char s[]){
int num = 0;
for(int i = 0; i < 4; ++i){ //一个数字的越前位,越大,所以正向处理
num = num*10 + (s[i]-'0');
}
return num;
}
代码:
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val) fill(a,a+n,val)
#define Scand(n) scanf("%d",&n)
#define Scans(s) scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 110000 + 5;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
int n;
char st[5],ed[5];
int ans;
bool notprime[10005];
int vis[10005];
struct node{
int num;
char numm[5];
int step;
};
void Init(){
memset(notprime, false, sizeof(notprime));
notprime[0] = notprime[1] = true;
for(int i = 2; i < 10005; ++i){
if(!notprime[i]){
if(i > 10005/i) continue;
for(int j = i*i; j < 10005; j +=i)
notprime[j] = true;
}
}
}
int chartonum(char s[]){
int num = 0;
for(int i = 0; i < 4; ++i){
num = num*10 + (s[i]-'0');
}
return num;
}
void bfs(){
queue<node> que;
node startt;
strcpy(startt.numm, st);
startt.num = chartonum(st);
startt.step = 0;
que.push(startt);
vis[startt.num] = 1;
while (!que.empty()) {
node now = que.front();
if(strcmp(now.numm, ed) == 0){
ans = min(ans, now.step);
return;
}
que.pop();
// printf("now: num:%d step:%d\n",now.num,now.step);
for(int i = 0; i < 4; ++i){
char temp[5];
strcpy(temp, now.numm);
// printf("i:%d temp:%s\n",i,temp);
for(int j = 0; j < 10; ++j){
temp[i] = '0'+j;
// printf("j:%d temp[%d]:%c\n",j,i,temp[i]);
if(strcmp(temp, now.numm) == 0)
continue;
int tempnum = chartonum(temp);
if(notprime[tempnum]) continue;
if(tempnum < 1000 || tempnum > 9999) continue;
if(vis[tempnum]) continue;
node nextt;
strcpy(nextt.numm, temp);
nextt.num = chartonum(nextt.numm);
nextt.step = now.step+1;
que.push(nextt);
vis[nextt.num] = 1;
// printf("success\n");
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
Init();
int n;
Scand(n);
fo(i, 0, n){
me(st, 0); me(ed, 0);
Scans(st); Scans(ed);
// printf("st:%s\ned:%s\n",st,ed);
ans = INF;
me(vis, 0);
bfs();
printf("%d\n",ans);
}
return 0;
}
G题:
题意:
类似于洗牌,给你两个字符串s1,s2,将s1,s2交叉插入,形成一个新字符串s,问能否得到给定的字符串。
思路:
由于整个过程都是固定唯一的,可以直接模拟这个过程,每次操作完,判断是否达到要求就行。其实就是一个递归函数,算不上dfs,好吧好吧,其实dfs不就是暴力递归吗。。。不过有一个问题就是,既然是递归,那么总得有一个终止条件吧,手算发现,经过一定次数的操作之后,s1,s2会回到一开始的s1,s2,那么以此作为终止条件就行。
技巧:
将s分割为s1和s2时,采用了strncpy函数。strncpy(字符数组名称,起始位置,切割长度)
代码:
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val) fill(a,a+n,val)
#define Scand(n) scanf("%d",&n)
#define Scand2(a,b) scanf("%d%d",&a,&b)
#define Scand3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s) scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e2 + 50;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
char a[maxn], b[maxn], c[2*maxn], together[2*maxn];
int success,cnt;
void fun(char a[], char b[]){
int len = strlen(a);
char temp[maxn*2];
int ind = 0;
for(int i = 0; i < len; ++i)
together[ind++] = b[i], together[ind++] = a[i];
// printf("temp:%s\n",temp);
// return temp;
}
void dfs(char x[], char y[]){
// printf("before:x:%s\ny:%s\n",x,y);
// printf("a:%s\nb:%s\nc:%s\n",a,b,c);
if(strcmp(x, a) == 0 && strcmp(y, b) == 0 && cnt){
return;
}
// char* together;
fi(together, maxn-5, 0);
fun(x, y);
cnt++;
// printf("together:%s\n",together);
if(strcmp(together, c) == 0){
success = 1;
return;
}
int len = strlen(together);
strncpy(x, together, len/2); strncpy(y, together+len/2, len/2);
// printf("after:x:%s\ny:%s\n",x,y);
dfs(x, y);
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
int T;
Scand(T);
for(int i = 1; i <= T; ++i){
fi(a, maxn-5, 0); fi(b, maxn-5, 0); fi(c, maxn-5, 0); fi(together, maxn-5, 0);
int n;
Scand(n);
Scans(a), Scans(b), Scans(c);
success = 0, cnt = 0;
// printf("a:%s\nb:%s\nc:%s\n",a,b,c);
char aa[maxn],bb[maxn];
strcpy(aa, a); strcpy(bb, b);
dfs(aa,bb);
if(success){
printf("%d %d\n",i,cnt);
}else{
printf("%d %d\n",i,-1);
}
}
return 0;
}
H题:
题意:
给你两个容器,分别能装下A升水和B升水,并且可以进行以下操作
FILL(i) 将第i个容器从水龙头里装满(1 ≤ i ≤ 2);
DROP(i) 将第i个容器抽干
POUR(i,j) 将第i个容器里的水倒入第j个容器(这次操作结束后产生两种结果,一是第j个容器倒满并且第i个容器依旧有剩余,二是第i个容器里的水全部倒入j中,第i个容器为空)
现在要求你写一个程序,来找出能使其中任何一个容器里的水恰好有C升,找出最少操作数并给出操作过程
思路:
在结构体中设置两个变量来表示两个瓶子中当前的水量。用bfs来遍历所有的可能,每一步有三种可能的操作。
另外由于要输出路径,所以要用数组模拟队列,并在结构体中设置了pre,路径中的第一个节点,也就是第一个入队的节点,将其的pre设为-1,之后入队的节点的pre设为父节点的数组下标。最后用递归函数打印路径,递归的终止条件是pre==-1。
还有就是由于选择第一种操作两种可能,所以进入循环前,要先push两个节点,也就是双入口bfs。
代码:
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val) fill(a,a+n,val)
#define Scand(n) scanf("%d",&n)
#define Scand2(a,b) scanf("%d%d",&a,&b)
#define Scand3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s) scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e6 + 50;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
struct node{
int id,order;
int step,resultt1,resultt2;
int pre;
};
node que[maxn];
int a,b,c;
int cnt = 0;
int success;
int vis[1000][1000];
void print(int num){
if(num == -1){
return;
}
print(que[num].pre);
if(que[num].order == 1){
printf("FILL(%d)\n",que[num].id);
}
else if(que[num].order == 2){
printf("DROP(%d)\n",que[num].id);
}else if(que[num].order == 3){
printf("POUR(%d,%d)\n",que[num].id,3-que[num].id);
}
}
void bfs(){
me(que, 0); me(vis, 0); success = 0;
node startt;
startt.order = 1; startt.id = 1; startt.pre = -1; startt.step = 1; startt.resultt1 = a; startt.resultt2 = 0;
int front = 0, rear = 0;
que[rear++] = startt;
startt.id = 2; startt.resultt2 = b; startt.resultt1 = 0;
que[rear++] = startt;
vis[0][0] = 1;
int flag = 0;
while (front < rear) {
node now = que[front];
if(now.resultt1 == c || now.resultt2 == c){
success = 1;
printf("%d\n",now.step);
print(front);
return ;
}
if(vis[now.resultt1][now.resultt2]){
front++;
continue;
}
vis[now.resultt1][now.resultt2] = 1;
if(now.resultt1 != a){
node nextt;
nextt.id = 1; nextt.order = 1; nextt.pre = front; nextt.resultt1 = a; nextt.step = now.step+1; nextt.resultt2 = now.resultt2;
que[rear++] = nextt;
}
if(now.resultt1 != 0){
node nextt;
nextt.id = 1; nextt.order = 2; nextt.pre = front; nextt.resultt1 = 0; nextt.step = now.step+1; nextt.resultt2 = now.resultt2;
que[rear++] = nextt;
}
if(now.resultt1 != 0){
node nextt;
nextt.id = 1; nextt.order = 3; nextt.pre = front; nextt.step = now.step+1;
if(now.resultt1+now.resultt2 > b){
nextt.resultt2 = b;
nextt.resultt1 = now.resultt1-(b-now.resultt2);
}else{
nextt.resultt2 = now.resultt1+now.resultt2;
nextt.resultt1 = 0;
}
que[rear++] = nextt;
}
if(now.resultt2 != b){
node nextt;
nextt.id = 2; nextt.order = 1; nextt.pre = front; nextt.resultt2 = b; nextt.step = now.step+1; nextt.resultt1 = now.resultt1;
que[rear++] = nextt;
}
if(now.resultt2 != 0){
node nextt;
nextt.id = 2; nextt.order = 2; nextt.pre = front; nextt.resultt2 = 0; nextt.step = now.step+1; nextt.resultt1 = now.resultt1;
que[rear++] = nextt;
}
if(now.resultt2 != 0){
node nextt;
nextt.id = 2; nextt.order = 3; nextt.pre = front; nextt.step = now.step+1;
if(now.resultt1+now.resultt2 > a){
nextt.resultt1 = a;
nextt.resultt2 = now.resultt2-(a-now.resultt1);
}else{
nextt.resultt1 = now.resultt1+now.resultt2;
nextt.resultt2 = 0;
}
que[rear++] = nextt;
}
front++;
}
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
while(Scand3(a, b, c) == 3){
bfs();
if(!success)
printf("impossible\n");
}
return 0;
}
I题:
题意:
两个熊孩子在n*m的平地上放火玩,#表示草,两个熊孩子分别选一个#格子点火,火可以向上向下向左向右在有草的格子蔓延,点火的地方时间为0,蔓延至下一格的时间依次加一。求烧完所有的草需要的最少时间。如不能烧完输出-1。
思路:
思路很简单,这题明显是双入口的bfs。先把可以烧的位置存进来,然后一个二重循环,遍历bfs 两个入口的位置,找出最优解就行。(这里要比较取优的原因在于,要进行多个bfs,每一个bfs求得的是最优解,然后在这些个最优解中取优)。
代码:
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val) fill(a,a+n,val)
#define Scand(n) scanf("%d",&n)
#define Scand2(a,b) scanf("%d%d",&a,&b)
#define Scand3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s) scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e4 + 50;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
struct node{
int x,y,step;
};
int n,m;
char mp[100][100];
int vis[100][100];
int ans, sum;
queue<node> que;
vector<node> v;
int dirx[] = {1,-1,0,0};
int diry[] = {0,0,1,-1};
void bfs(int x1, int y1, int x2, int y2){
me(vis, 0);
ans = 0;
while (!que.empty()) {
que.pop();
}
node startt;
startt.x = x1; startt.y = y1; startt.step = 0;
que.push(startt);
vis[x1][y1] = 1;
startt.x = x2; startt.y = y2; startt.step = 0;
que.push(startt);
vis[x2][y2] = 1;
while (!que.empty()) {
node now = que.front();
que.pop();
int xx = now.x; int yy = now.y; int stepp = now.step;
ans = stepp;
// int flag = 0;
for(int i = 0; i < 4; ++i){
int xxx = xx + dirx[i]; int yyy = yy + diry[i];
if(!(0 <= xxx && xxx < n) || !(0 <= yyy && yyy < m))
continue;
node nextt;
nextt.x = xxx; nextt.y = yyy; nextt.step = stepp+1;
if(mp[xxx][yyy] == '#' && !vis[xxx][yyy]){
que.push(nextt);
vis[xxx][yyy] = 1;
}
}
}
}
int judge(){
fo(i, 0, n)
fo(j, 0, m)
if(mp[i][j] == '#' && !vis[i][j])
return 0;
return 1;
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
int T;
while(Scand(T) != EOF){
for(int t = 1; t <= T; ++t){
Scand2(n, m);
me(mp, 0); me(vis, 0);
for(int i = 0; i < n; ++i)
Scans(mp[i]);
sum = 0;
v.clear();
for(int i = 0; i < n; ++i){
for(int j = 0; j < m; ++j){
if(mp[i][j] == '#'){
sum++;
node temp;
temp.x = i; temp.y = j; temp.step = 0;
v.push_back(temp);
}
}
}
int result = INF;
for(int i=0;i<v.size();i++)
{
for(int j=i;j<v.size();j++)
{
bfs(v[i].x,v[i].y,v[j].x,v[j].y);
int ok = judge();
if(ok)
{
result = min(result,ans);
}
}
}
if(result == INF)
result = -1;
printf("Case %d: %d\n",t,result);
}
}
return 0;
}
K题:
题意:
定义一个二维数组:
int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, };
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
思路:
很简单的bfs迷宫问题,由于要打印路径,得模拟队列+pre标记。
代码:
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
ll inv(ll a,ll m) { if(a == 1) return 1; return inv(m%a,m)*(m-m/a)%m; }
int lowbit(int x) { return x & (-x); }
const int maxn = 500000 + 100;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
struct node{
int x,y;
int pre;
}que[100];
int mp[10][10];
int vis[10][10];
int dirx[] = {0,0,1,-1};
int diry[] = {1,-1,0,0};
int check(int x, int y){
if(!(0 <= x && x <= 4)) return 0;
if(!(0 <= y && y <= 4)) return 0;
if(mp[x][y] == 1) return 0;
if(vis[x][y]) return 0;
return 1;
}
void print(int ind){
if(que[ind].pre != -1){
print(que[ind].pre);
printf("(%d, %d)\n",que[ind].x,que[ind].y);
}
}
void bfs(){
int front = 0, rear = 0;
que[rear].x = 0; que[rear].y = 0; que[rear].pre = -1;
rear++;
while(front < rear){
node now = que[front];
int x = now.x; int y = now.y;
//printf("now: x:%d y:%d\n",x,y);
if(x == 4 && y == 4){
//printf("front:%d\n",front);
print(front);
return ;
}
fo(i,0,4){
if(check(x+dirx[i],y+diry[i])){
que[rear].x = x+dirx[i];
que[rear].y = y+diry[i];
que[rear].pre = front;
//printf("next: x:%d y:%d\n",que[rear].x,que[rear].y);
rear++;
}
}
front++;
}
}
int main()
{
#ifndef ONLINE_JUDGE
Fin;
#endif // ONLINE_JUDGE
me(mp,0); me(vis,0);
fo(i,0,5)
fo(j,0,5)
cin >> mp[i][j];
cout << "(0, 0)" << endl;
bfs();
return 0;
}
L题:
题意:
给你一个字符矩阵,’*‘表示没油,’@‘表示有油,求图中油田的个数。
思路:
其实就是求连通块个数,直接用dfs搜一遍就行(遍历字符数组的每一个位置,如果是'@’,油田个数加一,再dfs其连通的'@',并做上标记)。
代码:
#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 100 + 5;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
int n,m;
char mp[maxn][maxn];
int vis[maxn][maxn];
int cnt;
int check(int x, int y){
if(!(0 <= x && x <= m-1)) return 0;
if(!(0 <= y && y <= n-1)) return 0;
if(mp[x][y] != '@' || vis[x][y]) return 0;
return 1;
}
void dfs(int x, int y){
for(int i = -1; i <= 1; ++i){
for(int j = -1; j <= 1; ++j){
if(!i && !j) continue;
if(check(x+i,y+j)){
vis[x+i][y+j] = 1;
dfs(x+i,y+j);
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
Fin;
#endif // ONLINE_JUDGE
while(cin >> m >> n){
getchar();
//printf("m:%d n:%d\n",m,n);
if(!n && !m) break;
me(mp,0);
fo(i,0,m){
scanf("%s",mp[i]);
//printf("i:%s\n",mp[i]);
}
/*fo(i,0,m){
fo(j,0,n)
cout << mp[i][j];
cout << endl;
}*/
cnt = 0; me(vis,0);
fo(i,0,m)
fo(j,0,n){
if(mp[i][j] == '@' && !vis[i][j]){
//printf("i:%d j:%d\n",i,j);
cnt++;
vis[i][j] = 1;
dfs(i,j);
}
}
cout << cnt << endl;
}
return 0;
}
M题:
题意:
只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升 (正好装满一瓶) ,它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。问两个人喝能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出"NO"。
思路:
和H题一样的题,只不过这里是3个容器,所以结构体需要三个变量分别记录三个容器剩下的可乐。这里不需要打印,不需要模拟队列,直接用STL中的queue就行。
代码:
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val) fill(a,a+n,val)
#define Scand(n) scanf("%d",&n)
#define Scand2(a,b) scanf("%d%d",&a,&b)
#define Scand3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s) scanf("%s",s)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e4 + 50;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
struct node{
int a,b,c;
int step;
node(int aa = 0, int bb = 0, int cc = 0, int stepp = 0){
a = aa; b = bb; c = cc; step = stepp;
}
};
int s,n,m;
queue<node> que;
int vis[200][200][200];
int ans;
void bfs(){
while (!que.empty()) {
que.pop();
}
fo(i, 0, 100)
fo(j, 0, 100)
fo(k, 0, 100)
vis[i][j][k] = 0;
node startt(s, 0, 0, 0);
que.push(startt);
while (!que.empty()) {
node now = que.front();
que.pop();
int a = now.a; int b = now.b; int c = now.c; int step = now.step;
if(vis[a][b][c]) continue;
vis[a][b][c] = 1;
// printf("a:%d b:%d c:%d step:%d\n",a,b,c,step);
if((!a && b == c) || (!b && a == c) || (!c && a == b)){
ans = step;
return;
}
if(a > 0){
if(a+b > n){
node nextt(a+b-n, n, c, step+1);
que.push(nextt);
}else if(a+b < n){
node nextt(0, a+b, c, step+1);
que.push(nextt);
}
if(a+c > m){
node nextt(a+c-m, b, m, step+1);
que.push(nextt);
}else if(a+c < m){
node nextt(0, b, a+c, step+1);
que.push(nextt);
}
}
if(b > 0){
if(b+a > s){
node nextt(s, b+a-s, c, step+1);
que.push(nextt);
}else if(b+a < s){
node nextt(b+a, 0, c, step+1);
que.push(nextt);
}
if(b+c > m){
node nextt(a, b+c-m, m, step+1);
que.push(nextt);
}else if(b+c < m){
node nextt(a, 0, b+c, step+1);
que.push(nextt);
}
}
if(c > 0){
if(c+a > s){
node nextt(s, b, c+a-s, step+1);
que.push(nextt);
}else if(c < s){
node nextt(c+a, b, 0, step+1);
que.push(nextt);
}
if(c+b > n){
node nextt(a, n, c+b-n, step+1);
que.push(nextt);
}else if(c+b < n){
node nextt(a, c+b, 0, step+1);
que.push(nextt);
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
while (Scand3(s, n, m) == 3) {
if(!s && !n && !m) break;
ans = 0;
bfs();
if(ans == 0)
printf("NO\n");
else
printf("%d\n",ans);
}
return 0;
}
N题:
题意:
一张图,上面有'@',两个人约定到其中的一个'@'中见面,求两人见面所花的最短时间。
思路:
可以求出两个人到达每一个'@'所花的时间,用两次bfs就行,然后对于每个'@',统计两人花费的时间(即两人分别所花时间相加),取最小值就行。
注意点:
bfs的终止条件是遍历完所有的'@',所以事先要记录图中'@'的个数。
代码:
#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define Scand(n) scanf("%d",&n);
#define Scans(s) scanf("%s",s);
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 110000 + 5;
const int INF = 0xffffff;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
struct node{
int x,y;
int step;
node(int a, int b, int c){
x = a; y = b; step = c;
}
};
int n,m;
char mp[250][250];
int vis1[250][250]; int vis2[250][250];
queue<node> que;
int stx1,sty1,stx2,sty2;
int cnt,num;
int dirx[] = {0,0,1,-1};
int diry[] = {1,-1,0,0};
int check(int x, int y){
if(!(1 <= x && x <= n)) return 0;
if(!(1 <= y && y <= m)) return 0;
if(mp[x][y] == '#' || mp[x][y] == 'Y' || mp[x][y] == 'M') return 0;
return 1;
}
void bfs1(){
num = 0;
while(!que.empty())
que.pop();
node startt(stx1,sty1,0);
vis1[stx1][sty1] = 0;
que.push(startt);
while(!que.empty()){
node now = que.front();
que.pop();
int x = now.x; int y = now.y; int step = now.step;
if(mp[x][y] == '@'){
num++;
if(num == cnt)
return;
}
fo(i,0,4){
int xx = x + dirx[i];
int yy = y + diry[i];
if(check(xx,yy) && !vis1[xx][yy]){
node nextt(xx,yy,step+1);
vis1[xx][yy] = step+1;
que.push(nextt);
}
}
}
}
void bfs2(){
num = 0;
while(!que.empty())
que.pop();
node startt(stx2,sty2,0);
vis1[stx2][sty2] = 0;
que.push(startt);
while(!que.empty()){
node now = que.front();
que.pop();
int x = now.x; int y = now.y; int step = now.step;
if(mp[x][y] == '@'){
num++;
if(num == cnt)
return;
}
fo(i,0,4){
int xx = x + dirx[i];
int yy = y + diry[i];
if(check(xx,yy) && !vis2[xx][yy]){
node nextt(xx,yy,step+1);
vis2[xx][yy] = step+1;
que.push(nextt);
}
}
}
}
int main()
{
while(cin >> n >> m){
me(mp,0); me(vis1,0); me(vis2,0);
cnt = 0;
fo(i,1,n+1){
scanf("%s",mp[i]+1);
fo(j,1,m+1){
if(mp[i][j] == 'Y'){
stx1 = i; sty1 = j;
}
if(mp[i][j] == 'M'){
stx2 = i; sty2 = j;
}
if(mp[i][j] == '@')
cnt++;
}
}
bfs1();
bfs2();
int ans = INF;
fo(i,1,n+1){
fo(j,1,m+1){
if(mp[i][j] == '@'){
if(!vis1[i][j] || !vis2[i][j])
continue;
ans = min(ans,vis1[i][j]+vis2[i][j]);
}
}
}
cout << ans*11 << endl;
}
return 0;
}