2019.3.5 kuangbin训练 poj3414 fzu2150(加练)
poj3414
题意:
跟平时说的倒水问题差不多。
给你2个空桶,容量分别为A
和B
,有以下操作:
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;
}