题意:
- 给两个空瓶子以及它们的容量A,B
- 三种操作
- 倒满A或者B
- 将A倒空或者将B倒空
- 将A倒入B或者将B倒入A(倒满或者倒完)
- 问任意一个瓶中的水达到C需要多少次操作
其实没有必要写题解…
唯一值得写的地方在于路径的输出:
- 对于一些不需要输出具体操作的题,我们可以直接将上一步的操作序号直接存在数组中,比如x,y<1e9,那么可以使pre[xx][yy]=x*1e9+y,取出来的时候取余递归即可。
- 对于需要输出操作顺序的题,我们可以直接开一个结构体,里面存着三个数组,分别记录前驱x,前驱y,以及操作i,这样可以避免在递归输出时额外花时间思考如何找出具体操作。
- 实际上,pre数组可以当作vis使用,但是在空间足够的情况下,为了代码的易读性,还是使用额外的标记数组进行标记。
#include<algorithm> #include <iostream> #include <cstdlib> #include <cstring> #include <cassert> #include <cstdio> #include <vector> #include <string> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> using namespace std; #define P(a,b,c) make_pair(a,make_pair(b,c)) #define rep(i,a,n) for (int i=a;i<=n;i++) #define per(i,a,n) for (int i=n;i>=a;i--) #define pb push_back #define mp make_pair #define all(x) (x).begin(),(x).end() #define fi first #define se second #define SZ(x) ((int)(x).size()) typedef pair<string,pair<int,int> > pii; typedef long long ll; const ll mod = 1000000007; ll gcd(ll a, ll b) { return b ? gcd(b, a%b) : a; } const int maxn=1e2+10; int A,B,goal; int vis[maxn][maxn],last[maxn][maxn],lasta[maxn][maxn],lastb[maxn][maxn]; char p[][10] = {{},{"FILL(1)"},{"FILL(2)"},{"DROP(1)"},{"DROP(2)"},{"POUR(1,2)"},{"POUR(2,1)"}}; struct status{ int a; int b; int step; status(int _a=0, int _b=0, int _step=0){ a=_a;b=_b;step=_step;; } }; void print(int a, int b){ if(last[a][b]!=0){ print(lasta[a][b],lastb[a][b]); printf("%s\n",p[ last[a][b] ]); } } void bfs(){ queue<status>q; int flag = 0; q.push(status(0,0,0)); vis[0][0] = 1; while(!q.empty()){ status t = q.front(); q.pop(); int a = t.a,b = t.b,step = t.step; if(a==goal||b==goal){ cout<<step<<endl; flag = 1; print(a,b); break; } int t_a,t_b; if(a!=0){ if(!vis[0][b]){//"DROP(1) q.push(status(0,b,step+1)); lasta[0][b] = a; lastb[0][b] = b; last[0][b] = 3; vis[0][b] = 1; } if(a+b>=B){//POUR(1,2) t_b = B; t_a = a+b-B; }else{ t_b = a+b; t_a = 0; } if(!vis[t_a][t_b]){ q.push(status(t_a,t_b,step+1)); lasta[t_a][t_b] = a; lastb[t_a][t_b] = b; last[t_a][t_b] = 5; vis[t_a][t_b] = 1; } } if(b!=0){ if(!vis[a][0]){//"DROP(2) q.push(status(a,0,step+1)); lasta[a][0] = a; lastb[a][0] = b; last[a][0] = 4; vis[a][0] = 1; } if(a+b>=A){//POUR(2,1) t_a = A; t_b = a+b-A; }else{ t_a = a+b; t_b = 0; } if(!vis[t_a][t_b]){ q.push(status(t_a,t_b,step+1)); lasta[t_a][t_b] = a; lastb[t_a][t_b] = b; last[t_a][t_b] = 6; vis[t_a][t_b] = 1; } } if(a!=A){ if(!vis[A][b]){ q.push(status(A,b,step+1)); lasta[A][b] = a; lastb[A][b] = b; last[A][b] = 1;//FILL(1) vis[A][b] = 1; } } if(b!=B){ if(!vis[a][B]){ q.push(status(a,B,step+1)); lasta[a][B] = a; lastb[a][B] = b; last[a][B] = 2;//FILL(2) vis[a][B] = 1; } } } if(!flag){ cout<<"impossible"; } }
一年以后重写代码:
//#include<bits/stdc++.h> #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<set> #include<vector> #include<map> #include<stack> #include<queue> #include<cmath> #include<fstream> #include<algorithm> using namespace std; #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,a,n) for(int i=n;i>=a;i--) //#define CLR(a) memset(a,sizeof(a),0) typedef long long ll; typedef unsigned long long ull; const int INF = 0x3f3f3f3f; const int maxn=1e6+10; int vis[200][200]; int pre[200][200]; int op[200][200]; int ans=0; int out[maxn]; int cnt=0; void bfs(int a,int b,int c){ memset(vis,0,sizeof(vis)); memset(pre,0,sizeof(pre)); queue<int>q; q.push(0); vis[0][0]=1; while(!q.empty()){ int t=q.front(); q.pop(); int x = t/1000; int y = t%1000; //cout<<x<<" "<<y<<endl; if(x==c||y==c){ ans = x*1000+y; break; } int tx=x,ty=y; if(!vis[a][y]){ pre[a][y]=x*1000+y; vis[a][y]=1; op[a][y]=1; q.push(a*1000+y); } if(!vis[x][b]){ pre[x][b]=x*1000+y; vis[x][b]=1; op[x][b]=2; q.push(x*1000+b); } if(!vis[0][y]){ pre[0][y]=x*1000+y; vis[0][y]=1; op[0][y]=3; q.push(0*1000+y); } if(!vis[x][0]){ pre[x][0]=x*1000+y; vis[x][0]=1; op[x][0]=4; q.push(x*1000+0); } if(x>=b-y)tx = x-(b-y),ty=b; else tx = 0,ty = y+x; if(!vis[tx][ty]){ pre[tx][ty]=x*1000+y; vis[tx][ty]=1; op[tx][ty]=5; q.push(tx*1000+ty); } if(y>a-x)ty = y-(a-x),tx=a; else ty = 0,tx = x+y; if(!vis[tx][ty]){ pre[tx][ty]=x*1000+y; vis[tx][ty]=1; op[tx][ty]=6; q.push(tx*1000+ty); } } } void dfs(int num){ if(num==0)return ; ++cnt; //if(cnt>10)return ; int x = num/1000; int y = num%1000; out[cnt]=op[x][y]; dfs(pre[x][y]); } int main(){ int a,b,c; cin>>a>>b>>c; bfs(a,b,c); if(ans!=0){ dfs(ans); // cout<<vis[0][5]<<endl; printf("%d\n",cnt); per(i,1,cnt){ if(out[i]==1){ puts("FILL(1)"); } if(out[i]==2){ puts("FILL(2)"); } if(out[i]==3){ puts("DROP(1)"); } if(out[i]==4){ puts("DROP(2)"); } if(out[i]==5){ puts("POUR(1,2)"); } if(out[i]==6){ puts("POUR(2,1)"); } } }else{ puts("impossible"); } return 0; }