HDUoj 1495非常可乐 三维BFS

本文介绍了一种解决可乐平分问题的算法,通过将问题转换为三维坐标中的点,利用广搜和数论技巧找到最少操作步数。提供了两种实现方式,一种是基于坐标变换的广搜算法,另一种是更简洁的数论解法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

拉了个搜索专题,这是第一道题。虽然之前就见过,可一直没有思路,这次重新写,终于AC。

思路就是把这个问题模型转换成三维坐标中的点,倒可乐就是坐标的变换,只要坐标满足条件即是可乐平分成功。

可乐奇数直接NO,然后广搜,广搜里的两层for也是一个技巧

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <numeric>
#include <cmath>
#include <cstdlib>
#include <string>
#include <map>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
#define el else
typedef long long LL;

struct point{
    int total;
    int a;
    int b;
    int st;
    point(int t,int aa,int bb,int ss)
        :total(t),a(aa),b(bb),st(ss)
    {}
};

const int maxn = 102;
bool vis[maxn][maxn][maxn];
int V[3];
int S,N,M;

int bfs(){
    point t(S,0,0,0);
    stack<point> s;
    s.push(t);
    while(!s.empty()){
        t = s.top();    s.pop();
        int a[3];
        //printf("t = %d %d %d\n",t.total,t.a,t.b);////
        if(t.a == S/2 && t.b == 0 || t.b == S/2 && t.a == 0){
            //printf("total = %d, a = %d, b = %d\n",t.total,t.a,t.b);////
            return t.st;
        }

        for(int i=0; i<3; ++i){
            for(int j=0; j<3; ++j)
            {
                a[0] = t.total, a[1] = t.a, a[2] = t.b;

                //printf("i = %d,a[i] = %d\n",i,a[i]);////
                //printf("j = %d,a[j] = %d\n",j,a[j]);////

                if(i != j && a[i]>0 && a[j]<V[j])
                {
                    //puts("in");////
                    if(a[i] >= V[j]-a[j]){
                        a[i] -= (V[j]-a[j]);
                        a[j] = V[j];
                    }//倒的比容量大
                    else{
                        a[j] += a[i];
                        a[i] = 0;
                    }//能到的没容量大

                    if(!vis[ a[0] ][ a[1] ][ a[2] ]){
                        vis[ a[0] ][ a[1] ][ a[2] ] = 1;

                        point shit(a[0],a[1],a[2],t.st+1);
                        //printf("shit = %d %d %d\n",shit.total,shit.a,shit.b);///
                        s.push(shit);
                    }
                }
            }
        }
    }
    return -1;
}

int main(){
    while(scanf("%d%d%d",&S,&N,&M),S!=0){

        if(S & 1){
            puts("NO");
            continue;
        }

        if(N > M)   N ^= M,M ^= N,N ^= M;

        V[0]=S, V[1]=N, V[2]=M;
        memset(vis,0,sizeof(vis));

        int step = bfs();

        step == -1 ? puts("NO") : printf("%d\n",step);
    }
    return 0;
}


But...Wait!

这个题还可以用数论来写,摘自:https://blog.youkuaiyun.com/V5ZSQ/article/details/52097459

è¿éåå¾çæè¿°

所以|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 
--------------------- 
作者:v5zsq 


来源:优快云 
原文:https://blog.youkuaiyun.com/V5ZSQ/article/details/52097459 
版权声明:本文为博主原创文章,转载请附上博文链接!

#include<cstdio>
#include<iostream>
using namespace std;
int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}
int main()
{
    int a,b,c;
    while(scanf("%d%d%d",&a,&b,&c),a+b+c)
    {
        a/=gcd(b,c);
        if(a&1)printf("NO\n");
        else printf("%d\n",a-1);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值