2019.3.5 kuangbin训练 poj3414 fzu2150(加练)

poj3414
题意:
跟平时说的倒水问题差不多。
给你2个空桶,容量分别为AB,有以下操作:
FILL(1) 装满1号桶
FILL(2) 装满2号桶
DROP(1) 清空1号桶
DROP(2) 清空2号桶
POUR(1,2) 将1号桶倒入2号桶(倒满则停)
POUR(2,1) 将2号桶倒入1号桶(倒满则停)
问当其中1个桶的水恰好等于C时,最少需要多少步?并输出步骤。
题解:
bfs
每一步有6种情况,对应上述6个
用二维数组vis[i][j]记录1号桶容量为i和2号桶容量为j时的情况,防止重复
这题主要是输出问题,不仅需要输出步数,还需要输出具体步骤
我用了一个二维数组pre[i][j]记录(i,j)的上一步状态,并在退出bfs时记录最终的1号桶容量、2号桶容量、最后一步的步骤
在结构体中加入了way变量(取值为1~6 对应上述6种方法)
通过最终的ansa、ansb、answay回溯寻找至pre[0][0]
用递归输出每一步的way即可
代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn=1e4;
int A,B,C,ans,ansa,ansb,answay;
int vis[107][107];
struct node
{
	int a,b;
	int step,way;
	node(int aa=0,int bb=0,int ss=0,int ww=0)
	{
		a=aa;b=bb;step=ss;way=ww;
	}
};
node pre[107][107];
void bfs()
{
	queue<node> q;
	while(!q.empty()) q.pop();
	q.push(node(0,0,0,0));
	vis[0][0]=1;
	while(!q.empty())
	{
		node temp=q.front();
		//printf("temp=%d %d %d %d\n",temp.a,temp.b,temp.step,temp.way);
		int step=temp.step;
		q.pop();
		if(temp.a==C || temp.b==C)
		{
			ansa=temp.a;
			ansb=temp.b;
			answay=temp.way;
			ans=temp.step;
			return;
		}
		// FILL(1)
		if(!vis[A][temp.b])
		{
			vis[A][temp.b]=1;
			pre[A][temp.b]=temp;
			q.push(node(A,temp.b,step+1,1));
		}
		// FILL(2)
		if(!vis[temp.a][B])
		{
			vis[temp.a][B]=1;
			pre[temp.a][B]=temp;
			q.push(node(temp.a,B,step+1,2));
		}
		// DROP(1)
		if(!vis[0][temp.b])
		{
			vis[0][temp.b]=1;
			pre[0][temp.b]=temp;
			q.push(node(0,temp.b,step+1,3));
		}
		// DROP(2)
		if(!vis[temp.a][0])
		{
			vis[temp.a][0]=1;
			pre[temp.a][0]=temp;
			q.push(node(temp.a,0,step+1,4));
		}
		// POUR(1,2)
		if(temp.a+temp.b<=B)
		{
			if(!vis[0][temp.a+temp.b])
			{
				vis[0][temp.a+temp.b]=1;
				pre[0][temp.a+temp.b]=temp;
				q.push(node(0,temp.a+temp.b,step+1,5));
			}
		}
		else
		{
			if(!vis[temp.a+temp.b-B][B])
			{
				vis[temp.a+temp.b-B][B]=1;
				pre[temp.a+temp.b-B][B]=temp;
				q.push(node(temp.a+temp.b-B,B,step+1,5));
			}
		}
		// POUR(2,1)
		if(temp.a+temp.b<=A)
		{
			if(!vis[temp.a+temp.b][0])
			{
				vis[temp.a+temp.b][0]=1;
				pre[temp.a+temp.b][0]=temp;
				q.push(node(temp.a+temp.b,0,step+1,6));
			}
		}
		else
		{
			if(!vis[A][temp.a+temp.b-A])
			{
				vis[A][temp.a+temp.b-A]=1;
				pre[A][temp.a+temp.b-A]=temp;
				q.push(node(A,temp.a+temp.b-A,step+1,6));
			}
		}
	}
}
void printway(int way)
{
	if(way==1)
		printf("FILL(1)\n");
	else if(way==2)
		printf("FILL(2)\n");
	else if(way==3)
		printf("DROP(1)\n");
	else if(way==4)
		printf("DROP(2)\n");
	else if(way==5)
		printf("POUR(1,2)\n");
	else if(way==6)
		printf("POUR(2,1)\n");
}
void findpre(int x,int y)
{
	if(pre[x][y].way==0)
		return;
	findpre(pre[x][y].a,pre[x][y].b);
	printway(pre[x][y].way);
}
void print()
{
	if(ans==-1)
		printf("impossible\n",ans);
	else printf("%d\n",ans);
	findpre(ansa,ansb);
	printway(answay);
}
int main()
{
	ans=-1;
	scanf("%d %d %d",&A,&B,&C);
	bfs();
	print();
	return 0;
}

fzu2150
题意:
给一个N*M矩阵 #表示草地 .表示空地
选择2处草地点火(可以同一地方),每1秒火会向四周蔓延,问烧完矩阵内所有草地最少需要多少秒?
题解:
首先题目说可以在不同时间点火,但没必要(不然要用优先队列)
根据贪心在一开始就点火可以达到最少时间
由于数据量少,暴力枚举2处点火的位置
将2个起点都加入到bfs中
跑完bfs检查是否还有草地没有烧完
最终取1个时间的最小值
!!!注意vector的清空 debug了好久!!!
代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int maxn=1e4;
int T,N,M,kase;
int ans;
char m[11][11];
int vis[11][11];
int X[]={-1,0,1,0};
int Y[]={0,1,0,-1};
struct node
{
	int x,y,t;
	node(int xx,int yy,int tt)
	{
		x=xx;y=yy;t=tt;
	}
};
vector<node> v; 
int bfs(node a,node b)
{
	int res=0;
	memset(vis,0,sizeof(vis));
	queue<node> q;
	while(!q.empty()) q.pop();
	q.push(a);
	q.push(b);
	vis[a.x][a.y]=1;
	vis[b.x][b.y]=1;
	while(!q.empty())
	{
		node temp=q.front();
		q.pop();
		res=max(res,temp.t);
		for(int i=0;i<4;i++)
		{
			int nx=temp.x+X[i];
			int ny=temp.y+Y[i];
			if(nx<0 || nx>=N || ny<0 || ny>=M)
				continue;
			if(m[nx][ny]=='#' && !vis[nx][ny])
			{
				vis[nx][ny]=1;
				q.push(node(nx,ny,temp.t+1));
			}
		}
	}
	return res;
}

int main()
{ 
	scanf("%d",&T);
	while(T--)
	{
		ans=maxn;
		v.clear();
		scanf("%d %d",&N,&M);
		for(int i=0;i<N;i++)
		{
			scanf("%s",m[i]);
			for(int j=0;j<M;j++)
				if(m[i][j]=='#')
					v.push_back(node(i,j,0));
		}
		for(int i=0;i<v.size();i++)
			for(int j=i;j<v.size();j++)
			{
				int res=bfs(v[i],v[j]);
				for(int k=0;k<v.size();k++)
					if(!vis[v[k].x][v[k].y])
					{
						res=maxn;
						break;
					}
				ans=min(ans,res);
			}
		if(ans==maxn)
			printf("Case %d: -1\n",++kase);
		else printf("Case %d: %d\n",++kase,ans);
		
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值