牛客——倒水问题

待学习。。

 

// Study.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
using namespace std;
/*将4杯子倒水问题改为一个足够大的杯子倒向4个杯子*/
bitset<17043521> Hash;/*(大小为64*64^4+64*64^3+64*64^2+64*64^1+64*64^0)记录每次操作后的ABCD杯子的当前容量是否已经存在过*/
const int MAX_STEP = 100000;
int WQ[MAX_STEP][6];/*记录每步操作后0和ABCD的当前容量,最后一个记录操作次数*/
int Goal[5];/*0和ABCD杯子最终状态*/
int Cap[5]; /*0和ABCD杯子的最大容量*/
int goalval;
int head = 0;
int tail = 0;
void movw(int numfrom, int numto, int other1, int other2, int other3)/*numfrom倒入numto*/
{
    int total = WQ[head][numfrom] + WQ[head][numto];/*numfrom和numto的总量*/
    WQ[tail][other1] = WQ[head][other1];
    WQ[tail][other2] = WQ[head][other2];
    WQ[tail][other3] = WQ[head][other3];
    WQ[tail][5] = WQ[head][5] + 1;

    if (total>Cap[numto])/*总量和被倒入杯子的容量大小;大于numfrom就有剩余的,否则全部倒入numto*/
    {
        WQ[tail][numfrom] = total - Cap[numto];
        WQ[tail][numto] = Cap[numto];
    }
    else
    {
        WQ[tail][numfrom] = 0;
        WQ[tail][numto] = total;
    }

    int hashval = WQ[tail][1] * 262144 + WQ[tail][2] * 4096 + WQ[tail][3] * 64 + WQ[tail][4];/*把ABCD杯子需要的状态抽象为一个值*/
    if (hashval == goalval) throw WQ[head][5] + 1;/*判断是否为最终状态*/

    if (!Hash[hashval])/*该次操作之后的状态之前未存在过并记录*/
    {
        Hash[hashval] = true;
        if (++tail == MAX_STEP) tail = 0;/*超出最大操作数*/
    }
}
int main()
{
    Hash.reset();
    scanf_s("%d %d %d %d", &Cap[1], &Cap[2], &Cap[3], &Cap[4]);
    scanf_s("%d %d %d %d", &Goal[1], &Goal[2], &Goal[3], &Goal[4]);
    head = 0;
    tail = 0;
    goalval = Goal[1] * 262144 + Goal[2] * 4096 + Goal[3] * 64 + Goal[4];/*把ABCD杯子需要的状态抽象为一个值*/
                                                                         /*处理全部杯子中最后容量都为0的情况*/
    if (Goal[1] == 0 && Goal[2] == 0 && Goal[3] == 0 && Goal[4] == 0) {
        printf("0");
        return 0;
    }
    Cap[0] = 6400;/*0杯子为足够大的杯子,0杯子的容量*/
    WQ[tail][0] = 6400;/*0杯子的当前容量*/
                       /*初始化ABCD杯子当前值为0*/
    WQ[tail][1] = 0;
    WQ[tail][2] = 0;
    WQ[tail][3] = 0;
    WQ[tail][4] = 0;
    WQ[tail][5] = 0;
    ++tail;
    try {
        /*尝试每一种操作*/
        while (head != tail)
        {
            /*A导入B,外层if判断A中当前容量不为零,内层判断B的最大容量不为0*/
            if (WQ[head][0]) {
                if (Cap[1])
                    movw(0, 1, 2, 3, 4);
                if (Cap[2])
                    movw(0, 2, 1, 3, 4);
                if (Cap[3])
                    movw(0, 3, 1, 2, 4);
                if (Cap[4])
                    movw(0, 4, 1, 2, 3);
            }

            if (WQ[head][1]) {
                if (Cap[0])
                    movw(1, 0, 2, 3, 4);
                if (Cap[2])
                    movw(1, 2, 0, 3, 4);
                if (Cap[3])
                    movw(1, 3, 0, 2, 4);
                if (Cap[4])
                    movw(1, 4, 0, 2, 3);
            }

            if (WQ[head][2]) {
                if (Cap[0])
                    movw(2, 0, 1, 3, 4);
                if (Cap[1])
                    movw(2, 1, 0, 3, 4);
                if (Cap[3])
                    movw(2, 3, 0, 1, 4);
                if (Cap[4])
                    movw(2, 4, 0, 1, 3);
            }

            if (WQ[head][3]) {
                if (Cap[0])
                    movw(3, 0, 1, 2, 4);
                if (Cap[1])
                    movw(3, 1, 0, 2, 4);
                if (Cap[2])
                    movw(3, 2, 0, 1, 4);
                if (Cap[4])
                    movw(3, 4, 0, 1, 2);
            }

            if (WQ[head][4]) {
                if (Cap[0])
                    movw(4, 0, 1, 2, 3);
                if (Cap[1])
                    movw(4, 1, 0, 2, 3);
                if (Cap[2])
                    movw(4, 2, 0, 1, 3);
                if (Cap[3])
                    movw(4, 3, 0, 1, 2);
            }

            if (++head == MAX_STEP) {
                head = 0;
            }
        }
        printf("-1");
    }
    catch (int step)
    {
        printf("%d\n", step);
    }
}

 

看了上面代码,自己给思路改进了一下,代码如下:

类似于图的广度优先遍历,每一种情况都一个个入队列,然后判断是否和预期的状态相等,相等时候停止循环,输出并返回。

// Study.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <string>
#include <algorithm>
using namespace std;

//存储每一种状态
bool m[64][64][64][64];
//int Step=0;
const int MaxStep = 10000;
vector<int> cap(4), goal(4);

class state {
public:
	state(int ra=0,int rb=0, int rc = 0, int rd = 0,int s = 0):a(ra),b(rb),c(rc),d(rd),step(s){}
	int a, b, c, d;
	int step;
};
queue<state> Queue({ 0,0,0,0 });
//Queue.push({ 0,0,0,0 });

//对序号k进行操作,装满,或者导入其他容器
void water_solution(int t[5],int k)
{
	int tmp = t[k];
	int tmp2;
	if (t[k] != cap[k] )
	{
		t[k] = cap[k];
		if(!m[t[0]][t[1]][t[2]][t[3]])
		{
			Queue.push({ t[0],t[1],t[2],t[3], t[4] + 1 });
			m[t[0]][t[1]][t[2]][t[3]] = 1;
		}
		t[k] = tmp;
	}

	//有剩余的水,可倒给其他杯子
	if (t[k] != 0)
	{
		for (int i = 0; i < 4; i++)
		{
			//对自己倒水,可以全部倒走
			if (k == i)
			{
				t[k] = 0;
				if (!m[t[0]][t[1]][t[2]][t[3]])
				{
					Queue.push({ t[0],t[1],t[2],t[3], t[4] + 1 });
					m[t[0]][t[1]][t[2]][t[3]] = 1;
				}
				t[k] = tmp;
				continue;
			}

			//倒给别人,1:倒不完
			if (t[k] + t[i] >= cap[i])
			{
				tmp2 = t[i];
				t[i] = cap[i];
				t[k] = t[k] - (cap[i] - tmp2);
				if (!m[t[0]][t[1]][t[2]][t[3]])
				{
					Queue.push({ t[0],t[1],t[2],t[3], t[4] + 1 });
					m[t[0]][t[1]][t[2]][t[3]] = 1;
				}
				t[k] = tmp;
				t[i] = tmp2;
			}
			else
			{
				tmp2 = t[i];
				t[i] += t[k];
				t[k] = 0;
				if (!m[t[0]][t[1]][t[2]][t[3]])
				{
					Queue.push({ t[0],t[1],t[2],t[3], t[4] + 1 });
					m[t[0]][t[1]][t[2]][t[3]] = 1;
				}

				t[k] = tmp;
				t[i] = tmp2;
			}
		}
	}
}
int main()
{

	for (int i = 0; i < 4; i++)
		cin >> cap[i];
	for (int i = 0; i < 4; i++)
		cin >> goal[i];


	int t[5];
	state current{0,0,0,0};
	int k = 0;
	while (!Queue.empty())
	{
		current = Queue.front();
		t[0] = current.a; t[1] = current.b; t[2] = current.c; t[3] = current.d; t[4] = current.step;
		Queue.pop();

		if (t[0] == goal[0] && t[1] == goal[1] && t[2] == goal[2] && t[3] == goal[3])
		{
			cout << t[4];
			system("pause");
			return 0;
		}

		for(int i=0;i<4;i++)
			water_solution(t, i);

	}
	cout << -1;
	system("pause");
	return 0;
}

  

posted @ 2018-08-23 11:48  何许  阅读(357)  评论(0编辑  收藏  举报