• 牛客——倒水问题


    待学习。。

    // 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
    ", 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;
    }
    

      

  • 相关阅读:
    VueCLI3如何更改安装时的包管理器
    查天气43课-46课
    【Python第31课到42课】
    【Python第16课到30课 】
    Python笔记
    【AC】九度OJ题目1153:括号匹配问题
    【AC】九度OJ题目1436:Repair the Wall
    【WA】九度OJ题目1435:迷瘴
    Matlab图片改颜色通道不改名存储
    [Linux 操作] awk操作の 打印图片路径
  • 原文地址:https://www.cnblogs.com/Oscar67/p/9518420.html
Copyright © 2020-2023  润新知