[kuangbin带你飞]专题一 简单搜索

没想到这么久没写博客了!之前蓝桥杯省赛加校赛一直没空补博客内容....(打水漂真的挺好玩的)

  最近开始补kuangbin专题,虽然是简单搜索。。。但是做着一点都不简单= =

A - 棋盘问题

  POJ - 1321

第一题,大意是说给个棋盘(矩形),有可放棋子的地方和不可放棋子的地方,给定需要放的棋子数,且一行或一列只允许有一个棋子,求一共的方案数。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

  POJ - 2251

题目大意:一个类似塔的迷宫,每一个格子可以跳上一层或者落下一层,以及上下左右,找出最少时间。

这题让我注意到了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();
	}
}
C - Catch That Cow

题目大意:一个牛在一个直线上,而放牛人可以走三种①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;
}

D - Fliptile

  POJ - 3279 
题目大意:奶牛要翻砖块,黑色和白色,需要全白。给了一个矩阵,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

 POJ - 1426

题目大意:给一个数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;
}

G - Shuffle'm Up

题目大意:


按如图所示的方式将两个牌堆合在一起,求合几次能得到与题目要求相同的牌堆,若永远无法得到,输出-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;
	}
}

H - Pots

  POJ - 3414 

题目大意:输入两个容器的容量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

  FZU - 2150 

题目大意:给一片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!

  UVA - 11624 

题目大意:给一个地图,一个地方是火一个地方是人,火会往四个方向蔓延,看人能否找到一条最短路且不被火烧的的情况先逃生到地图外。

思路:直接先把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 - 迷宫问题

  POJ - 3984 

题目大意:给一个矩阵,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

  HDU - 1241 

题目大意:给一个地图#代表路,@代表油,如果油的九宫格还有其他油,这些油属于同一种油,问一一共有几种油

思路:遇到@就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 - 非常可乐

  HDU - 1495 

题意:有一瓶可乐,两个空瓶子,问最少几次可以倒成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

  HDU - 2612 

题目大意:给一个地图,有两个人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;
} 

拖拖拉拉终于把专题一写完了。。后面的专题一定不会再多于一周了!!




 

猜你喜欢

转载自blog.csdn.net/doneone_/article/details/80114968