题目链接:Pots
解析:给定两个水瓶的大小a和b,以及目标c,输出最短操作使某一水瓶中剩下c容量的水。操作包括倒空、倒满、两瓶互相倒。
解法一:DFS
枚举每次可行的方案,并对枚举的上限做了限制,即如果当前的枚举次数已经大于目前最小次数解就剪枝。
AC代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int c, n, m, ans;
bool vis[110][110], tg;
char pa[10010][20], pp[10010][20];
void dfs(int x, int y, int dep){
if(dep > ans) return ;
if(x == c || y == c){
if(dep < ans){
ans = dep;
tg = true;
for(int i=0; i<ans; i++)
strcpy(pa[i], pp[i]);
}
return ;
}
//FILL 1
if(x < n && !vis[n][y]){
vis[n][y] = true;
strcpy(pp[dep], "FILL(1)");
dfs(n, y, dep+1);
vis[n][y] = false;
}
//FILL 2
if(y < m && !vis[x][m]){
vis[x][m] = true;
strcpy(pp[dep], "FILL(2)");
dfs(x, m, dep+1);
vis[x][m] = false;
}
//DROP 1
if(x > 0 && !vis[0][y]){
vis[0][y] = true;
strcpy(pp[dep], "DROP(1)");
dfs(0, y, dep+1);
vis[0][y] = false;
}
//DROP 2
if(y > 0 && !vis[x][0]){
vis[x][0] = true;
strcpy(pp[dep], "DROP(2)");
dfs(x, 0, dep+1);
vis[x][0] = false;
}
//POUR 1 -> 2
if(x > 0 && y < m){
int t = min(x, m-y);
if(!vis[x-t][y+t]){
vis[x-t][y+t] = true;
strcpy(pp[dep], "POUR(1,2)");
dfs(x-t, y+t, dep+1);
vis[x-t][y+t] = false;
}
}
//POUR 2 -> 1
if(y > 0 && x < n){
int t = min(y, n-x);
if(!vis[x+t][y-t]){
vis[x+t][y-t] = true;
strcpy(pp[dep], "POUR(2,1)");
dfs(x+t, y-t, dep+1);
vis[x+t][y-t] = false;
}
}
}
int main(){
// freopen("in.txt", "r", stdin);
while(scanf("%d%d%d", &n, &m, &c) == 3){
memset(vis, false, sizeof(vis));
ans = 0x7fffffff;
tg = false;
vis[0][0] = true;
dfs(0, 0, 0);
if(tg){
printf("%d\n", ans);
for(int i=0; i<ans; i++)
puts(pa[i]);
}
else puts("impossible");
}
return 0;
}