分红酒

来源:互联网 发布:linux tomcat安装版 编辑:程序博客网 时间:2024/04/27 04:34

问题描述:

有4个红酒瓶子,它们的容量分别是:9升, 7升, 4升, 2升
  
  开始的状态是 [9,0,0,0],也就是说:第一个瓶子满着,其它的都空着。


  允许把酒从一个瓶子倒入另一个瓶子,但只能把一个瓶子倒满或把一个瓶子倒空,不能有中间状态。这样的一次倒酒动作称为1次操作。


  假设瓶子的容量和初始状态不变,对于给定的目标状态,至少需要多少次操作才能实现?


  本题就是要求你编程实现最小操作次数的计算。
 
  输入:最终状态(逗号分隔)
  输出:最小操作次数(如无法实现,则输出-1)


输入:
9,0,0,0
应该输出:
0


输入:
6,0,0,3
应该输出:
-1


输入:
7,2,0,0
应该输出:
2


分析:

采用宽度优先遍历,枚举出分酒的每个状态,满足给定条件退出。


#include<cstdio>#include<cstring>#include<cstdlib>#define MAXN 100#define min(a,b) a<b?a:btypedef struct node{    int state[4];    int step;}Node;int vis[MAXN][MAXN][MAXN];int a, b, c, d;int cap[4] = {9,7,4,2};void bfs(){    Node n;    n.state[1] = n.state[2] = n.state[3] = 0;   //初始化状态    n.state[0] = 9;    n.step = 0;    Node q[1000];    int front = 0, rear = 1;    q[front] = n;    vis[n.state[1]][n.state[2]][n.state[3]] = 1;    while(front < rear)    {        Node p = q[front];  //出队        if(p.state[0] == a && p.state[1] == b && p.state[2] == c && p.state[3] == d)        {            printf("%d\n",p.step);            return;        }        for(int i = 0; i < 4; i++)                  //枚举倒入一次的状态        {            for(int j = 0; j < 4; j++)            {                if(i == j) continue;                Node p1 = p;                int count = min(p.state[i],cap[j]-p.state[j]);//判断两瓶子水容量大小                p1.state[i] -= count;                p1.state[j] += count;                p1.step++;                if(!vis[p1.state[1]][p1.state[2]][p1.state[3]])                {                    vis[p1.state[1]][p1.state[2]][p1.state[3]] = 1;                    q[rear++] = p1;     //入队                }            }        }        front++;    }    printf("-1\n");}int main(){    memset(vis,0,sizeof(vis));    scanf("%d%d%d",&a,&b,&c);    bfs();    return 0;}


0 0