ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

#1495:非常可乐(BFS+数论)

2020-05-09 09:57:29  阅读:267  来源: 互联网

标签:cnt temp int sign BFS step 1495 include 可乐


题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1495

BFS解法

题目 给三个数字 s n m s=n+m s在1到100之间

就是个倒水问题可以从第一个倒向第二个 类似的一共可以有六中到发

现在要求最少经过多少步就能平分那么多水

首先剪枝是 如果s是奇数必然不行。

一看到要求最少的步数就知道用bfs了

我们用vis标记状态

每个状态有三个整数组成 表示这三个杯子里的可乐数量

然后对每个状态的递推是 6种 也就是3!种。从一个到到另一个 再标记 入队

#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
int v[5];
bool sign[110][110][110];
/*
我们用sign标记状态
每个状态有三个整数组成 表示这三个杯子里的可乐数量
*/
struct cup {
    int v[5];
    int step;
    cup() { v[0] = v[1] = v[2] = v[3] = step = 0; }
}temp;

void pour(int a, int b)//倒水函数,把a杯子中的可乐倒到b杯子中
{
    int sum = temp.v[a] + temp.v[b];
    if (sum >= v[b])
        temp.v[b] = v[b];
    else
        temp.v[b] = sum;
    temp.v[a] = sum - temp.v[b];
}

void bfs()
{
    int i, j;
    queue<cup>q;
    cup cnt;
    cnt.v[1] = v[1];
    cnt.v[2] = 0;
    cnt.v[3] = 0;
    cnt.step = 0;
    q.push(cnt);
    memset(sign, 0, sizeof(sign));
    sign[v[1]][0][0] = 1;
    while (!q.empty())
    {
        cnt = q.front();
        q.pop();
        if (cnt.v[1] == cnt.v[3] && cnt.v[2] == 0)
        {
            printf("%d\n", cnt.step);
            return;
        }
        for (i = 1; i < 4; ++i)
        {
            for (j = 1; j < 4; ++j)
            {
                if (i != j)//自己不倒水给自己  
                {
                    temp = cnt;//每个水位情况都要把所有操作枚举一遍,所以都要赋值为原始水位情况  
                    pour(i, j);
                    if (!sign[temp.v[1]][temp.v[2]][temp.v[3]])
                    {
                        temp.step++;
                        q.push(temp);
                        sign[temp.v[1]][temp.v[2]][temp.v[3]] = 1;
                    }
                }
            }
        }
    }
    printf("NO\n");
}

int main()
{
    while (scanf("%d%d%d", &v[1], &v[2], &v[3]) && v[1] || v[2] || v[3])
    {
        if (v[2] > v[3])
            swap(v[2], v[3]);
        bfs();
    }
    return 0;
}

利用数论的神仙题解

分析:设两个小瓶子容积分别为a,b,问题转化成通过两个小瓶子的若干次倒进或倒出操作得到(a+b)/2体积的可乐,设两个小瓶子被倒进或倒出x次和y次(这里的x和y是累加后的操作,即x=第一个瓶子倒出的次数-倒进的次数,y=第二个瓶子倒出的次数-倒进的次数),那么问题转化成:

所以|x+|y|的最小值为(c+d)/2,通过x和y的通解形式显然可以看出x和y一正一负,不妨设x<0,那么就是往第一个小瓶子倒进x次,第二个小瓶子倒出y次,但是由于瓶子容积有限,所以倒进倒出操作都是通过大瓶子来解决的,一次倒进操作后为了继续使用小瓶子还要将小瓶子中可乐倒回大瓶子中,倒出操作同理,所以总操作次数是(c+d)/2*2=c+d,但是注意最后剩下的(a+b)/2体积的可乐一定是放在两个小瓶子中较大的那个中,而不是再倒回到大瓶子中,所以操作数要减一,答案就是c+d-1
下面给出AC代码:

#include <bits/stdc++.h>
using namespace std;
int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}
int main()
{
    int a,b,c;
    while(cin>>a>>b>>c&&(a&&b&&c))
    {
        a/=gcd(b,c);
        if(a&1)
            cout<<"NO"<<endl;
        else
            cout<<a-1<<endl;
    }
    return 0;
}

标签:cnt,temp,int,sign,BFS,step,1495,include,可乐
来源: https://www.cnblogs.com/RioTian/p/12855376.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有