题解:【PA2021】Butelki
设三个瓶子分别为 \(x\)、\(y\)、\(z\),考虑一次操作只会有一个瓶子倒向另一个瓶子,所以最多延伸出六个新状态:\(x \to y\)、\(x \to z\)、\(y \to x\)、\(y \to z\)、\(z \to x\)、\(z \to y\)。每种状态都有两种可能,一个是倒空了当前的瓶子,另一个是倒满了要倒的瓶子。
不妨记三个瓶子初始的水量为 \(a,b,c\),一次操作过后,必定有一个瓶子是满的或者空的,钦定 \(a\) 是满的,那么剩下两个瓶子的状态数便是这三种情况之一:
\[\min\{b,c\} +
\begin{cases}
\min\{a,b\} + \min\{a,c\} \\
\min\{a,b\} + 1 \\
\min\{a,c\} + 1
\end{cases}
\]
于是得到了一个 \(2a + 2b + 2c +2 \times 3 + 1\) 数量的状态上界,其中 \(2 \times 3\) 为六种不同倒的情况,\(1\) 为初始状态,足以证明是状态数是线性增长的。因此尽管数据范围有 \(10^5\),依然可以直接记忆化搜索。
记录只需要记三个瓶子的容量和当前状态的步数,直接压到一个数里面就好,这样也方便判重。
其他细节直接看代码罢。
\(Code\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int s=0,w=1;
char c=getchar();
while(!isdigit(c)) {if(c=='-') w=-1; c=getchar();}
while(isdigit(c)) s=(s<<1)+(s<<3)+(c^48),c=getchar();
return s*w;
}
namespace LgxTpre
{
static const int MAX=100010;
static const int INF=4557430888798830399;
static const int mod=998244353;
static const int puz=1000000;
int x_start,y_start,z_start;
int ans[MAX];
int up[4],bot[4],tmp[4],goal;
queue<pair<int,int> > q;
map<int,bool> mp;
inline int get(int x,int y,int z)
{
return x*1000000000000+y*1000000+z;
}
inline void pullin(int tim)
{
int now=get(tmp[1],tmp[2],tmp[3]);
if(mp.find(now)!=mp.end()) return;
q.push(make_pair(now,tim));
mp[now]=1;
return;
}
inline void lmy_forever()
{
memset(ans,0x3f,sizeof ans);
up[1]=read(),up[2]=read(),up[3]=read(); goal=up[3];
x_start=read(),y_start=read(),z_start=read();
q.push(make_pair(get(x_start,y_start,z_start),0));
while(!q.empty())
{
int now=q.front().first,tim=q.front().second; q.pop();
bot[3]=now%puz,now/=puz,ans[bot[3]]=min(ans[bot[3]],tim);
bot[2]=now%puz,now/=puz,ans[bot[2]]=min(ans[bot[2]],tim);
bot[1]=now%puz,now/=puz,ans[bot[1]]=min(ans[bot[1]],tim);
for(int i=1;i<=3;++i)
for(int j=1;j<=3;++j)
{
if(i==j) continue;
int sum=bot[i]+bot[j];
memcpy(tmp,bot,sizeof bot);
if(sum>=up[j]) tmp[i]=sum-up[j],tmp[j]=up[j],pullin(tim+1);
else tmp[i]=0,tmp[j]=sum,pullin(tim+1);
}
}
for(int i=0;i<=goal;++i)
cout<<(ans[i]==INF?-1:ans[i])<<" ";
return;
}
}
signed main()
{
LgxTpre::lmy_forever();
return (0-0);
}