题意: 你有两个罐子,容量分别为a,b;开始时都没水,要通过给定的三种操作,使得其中一个罐子的水量恰好为c,若存在操作使之成立,输出最少操作数及对应的每步操作;否则输出impossible。
思路: 由于a,b,c的范围很小为1到100且要求最小操作数,故考虑采用bfs,即搜索可能的情况若有到达其中一个罐子里的水为c的情况则搜索结束并输出路径,否则直到队列为空后输出impossible。
对于路径的输出,用于a,b的范围都在100之内,故开一个100*100的数组pre即可存储所有可能的搜索情况,pre数组的作用是记录bfs中当前状态的前一个转移过来的状态,输出时用栈将数据倒过来即可。
(第一次写时采用在结构体中新开一个node * pre来记录前驱,但是指针涉及到了动态开空间会超时…)
AC代码(pre数组记录前驱):
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
#include<string>
#include<stack>
using namespace std;
#define maxn 105
bool vis[maxn][maxn];//标记已经搜过的状态,避免重复搜索;
string op[]={"FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"};
struct node{
int x,y;
int step;
int id;
};
struct pre{
int id;
int operation;
}pre[maxn*maxn];//存前驱节点;
int a,b,c;
void get_ans(node now)
{
printf("%d\n",now.step);
stack<int>st;
while(!st.empty()) st.pop();
int pos=now.id;
while(pre[pos].id!=-1)
{
st.push(pre[pos].operation);
pos=pre[pos].id;
}
while(!st.empty())
{
int t=st.top();
st.pop();
cout<<op[t]<<endl;
}
}
void bfs()
{
queue<node>q;
int pos=0;//记录是第几个状态,便于找路径;
while(!q.empty()) q.pop();
memset(vis,false,sizeof(vis));
node s;
s.x=0;
s.y=0;
s.step=0;
s.id=0;
pre[0].id=-1;
pre[0].operation=-1;
vis[0][0]=true;
q.push(s);
while(!q.empty())
{
node now=q.front();
q.pop();
if(now.x==c||now.y==c)
{
get_ans(now);
return ;
}
node in;
in.step=now.step+1;
//1.a装满;
if(now.x>=0 && now.x<a && (!vis[a][now.y]))
{
in.x=a;
in.y=now.y;
in.id=(++pos);
pre[in.id].operation=0;
pre[in.id].id=now.id;
q.push(in);
vis[in.x][in.y]=true;
}
//2.b装满;
if(now.y>=0 && now.y<b && (!vis[now.x][b]))
{
in.x=now.x;
in.y=b;
in.id=(++pos);
pre[in.id].operation=1;
pre[in.id].id=now.id;
q.push(in);
vis[in.x][in.y]=true;
}
//3.a倒空;
if(now.x>0 && (!vis[0][now.y]))
{
in.x=0;
in.y=now.y;
in.id=(++pos);
pre[in.id].operation=2;
pre[in.id].id=now.id;
q.push(in);
vis[in.x][in.y]=true;
}
//4.b倒空;
if(now.y>0 && (!vis[now.x][0]))
{
in.x=now.x;
in.y=0;
in.id=(++pos);
pre[in.id].operation=3;
pre[in.id].id=now.id;
q.push(in);
vis[in.x][in.y]=true;
}
//5.a能够全部倒入b中;
if(now.x>0 && now.x+now.y<=b && (!vis[0][now.x+now.y]))
{
in.x=0;
in.y=now.x+now.y;
in.id=(++pos);
pre[in.id].operation=4;
pre[in.id].id=now.id;
q.push(in);
vis[in.x][in.y]=true;
}
//6.b能够全部倒入a中;
if(now.y>0 && now.x+now.y<=a && (!vis[now.x+now.y][0]))
{
in.x=now.x+now.y;
in.y=0;
in.id=(++pos);
pre[in.id].operation=5;
pre[in.id].id=now.id;
q.push(in);
vis[in.x][in.y]=true;
}
//7.a只有部分能倒入b中;
if(now.x>0 && now.x+now.y>b && (!vis[now.x-(b-now.y)][b]))
{
in.x=now.x-(b-now.y);
in.y=b;
in.id=(++pos);
pre[in.id].operation=4;
pre[in.id].id=now.id;
q.push(in);
vis[in.x][in.y]=true;
}
//8.b只有部分能倒入a中;
if(now.y>0 && now.x+now.y>a && (!vis[a][now.y-(a-now.x)]))
{
in.x=a;
in.y=now.y-(a-now.x);
in.id=(++pos);
pre[in.id].operation=5;
pre[in.id].id=now.id;
q.push(in);
vis[in.x][in.y]=true;
}
}
printf("impossible\n");
}
int main()
{
scanf("%d%d%d",&a,&b,&c);
bfs();
return 0;
}
超时代码(node* pre结构体指针记录前驱):
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
#include<string>
#include<stack>
using namespace std;
bool vis[105][105];//标记已经搜过的状态,避免重复搜索;
string op[]={"FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"};
struct node{
int x,y;
int step;
int operation;
node* pre;
};
int a,b,c;
void bfs()
{
queue<node>q;
while(!q.empty()) q.pop();
memset(vis,false,sizeof(vis));
node* s=(node*)malloc(sizeof(node));
s->x=0;
s->y=0;
s->step=0;
q.push(*s);
s->pre=NULL;
vis[0][0]=true;
while(!q.empty())
{
node* now=(node*)malloc(sizeof(node));
now=&q.front();
q.pop();
if(now->x==c||now->y==c)//有一个罐子满足终止条件
{
printf("%d\n",now->step);
stack<int>st;
while(!st.empty()) st.pop();
while(now->pre!=NULL)
{
st.push(now->operation);
now=now->pre;
}
while(!st.empty())
{
int t=st.top();
st.pop();
cout<<op[t]<<endl;
}
return ;
}
node* in=(node*)malloc(sizeof(node));
in->step=now->step +1;
in->pre=now;
//1.a装满;
if(now->x>=0 && now->x<a && (!vis[a][now->y]))
{
in->x=a;
in->y=now->y;
now->operation=0;
q.push(*in);
vis[in->x][in->y]=true;
}
//2.b装满;
if(now->y >=0 && now->y<b &&(!vis[now->x][b]))
{
in->x=now->x;
in->y=b;
now->operation=1;
q.push(*in);
vis[in->x][in->y]=true;
}
//3.a倒空;
if(now->x>0 && (!vis[0][now->y]))
{
in->x=0;
in->y=now->y;
now->operation=2;
q.push(*in);
vis[in->x][in->y]=true;
}
//4.b倒空;
if(now->y>0 && (!vis[now->x][0]))
{
in->x=now->x;
in->y=0;
now->operation=3;
q.push(*in);
vis[in->x][in->y]=true;
}
//5.能把a全部倒入b;
if(now->x>0 && now->y+now->x <=b && (!vis[0][now->x+now->y]))
{
in->x=0;
in->y=now->x+now->y;
now->operation=4;
q.push(*in);
vis[in->x][in->y]=true;
}
//6.能把b全部倒入a;
if(now->y>0 && now->x+now->y <=a && (!vis[now->x+now->y][0]))
{
in->x=now->x+now->y;
in->y=0;
now->operation=5;
q.push(*in);
vis[in->x][in->y]=true;
}
//7.只能倒一部分a到b中;
if(now->x>0 && now->x+now->y >b && (!vis[now->x-(b-now->y)][b]))
{
in->x=now->x-(b-now->y);
in->y=b;
now->operation=4;
q.push(*in);
vis[in->x][in->y]=true;
}
//8.只能倒一部分b到a中;
if(now->y>0 && now->x+now->y >a && (!vis[a][now->y-(a-now->x)]))
{
in->x=a;
in->y=now->y-(a- now->x);
now->operation=5;
q.push(*in);
vis[in->x][in->y]=true;
}
}
printf("impossible\n");
}
int main()
{
int i,j;
scanf("%d%d%d",&a,&b,&c);
bfs();
return 0;
}