HDU-1495 非常可乐 (嵌套结构体-广搜 对比 一般广搜)
题意
Input
三个整数 : S 可乐的体积 , N 和 M是两个杯子的容量,以"0 0 0"结束。Output如果能平分的话请输出最少要倒的次数,否则输出"NO"。Sample Input
7 4 3
4 1 3
0 0 0
Sample Output
NO
3
---------------------------------------------------------我是分割线----------------------------------------------------------------------------------------------------------------------
某童靴的一般思路 (感谢@陌类 提供的代码)
(较麻烦的题解, 好像多数人都这么写~
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#define N 110
using namespace std;
int vis[N][N][N];
int s,n,m;
struct node
{
int n,s,m,step;
};
int cheak(int x,int y,int z)
{
if(x==&&y==z)
return ;
if(y==&&x==z)
return ;
if(z==&&x==y)
return ;
return ;
}
int bfs()
{
queue<node>Q;
node now,next;
now.s=s;
now.n=;
now.m=;
now.step=;
vis[s][][]=;
Q.push(now);
while(Q.size())
{
now=Q.front();
Q.pop();
if(cheak(now.s,now.n,now.m))//检查状态
{
return now.step;
}
for(int i=;i<=;i++)
{
if(now.s!=)
{
if(i==&&now.n!=n)
{
if(now.n+now.s>n)
{
next.n=n;
next.s=now.s-(n-now.n);
}
else
{
next.n=now.n+now.s;
next.s=;
}
next.m=now.m;
next.step=now.step+;
if(!vis[next.s][next.n][next.m])
{
vis[next.s][next.n][next.m]=;
Q.push(next);
}
}
else if(i==&&now.s!=&&now.m!=m)
{
if(now.m+now.s>m)
{
next.m=m;
next.s=now.s-(m-now.m);
}
else
{
next.m=now.m+now.s;
next.s=;
}
next.n=now.n;
next.step=now.step+;
if(!vis[next.s][next.n][next.m])
{
vis[next.s][next.n][next.m]=;
Q.push(next);
}
}
}
if(now.n!=)
{
if(i==&&now.m!=m)
{
if(now.m+now.n>m)
{
next.m=m;
next.n=now.n-(m-now.m);
}
else
{
next.m=now.m+now.n;
next.n=;
}
next.s=now.s;
next.step=now.step+;
if(!vis[next.s][next.n][next.m])
{
vis[next.s][next.n][next.m]=;
Q.push(next);
}
}
else if(i==&&now.n!=&&now.s!=s)
{
if(now.m+now.s>s)
{
next.s=s;
next.n=now.n-(s-now.s);
}
else
{
next.s=now.n+now.s;
next.n=;
}
next.m=now.m;
next.step=now.step+;
if(!vis[next.s][next.n][next.m])
{
vis[next.s][next.n][next.m]=;
Q.push(next);
}
}
}
if(now.m!=)
{
if(i==&&now.m!=&&now.n!=n)
{
if(now.n+now.m>n)
{
next.n=n;
next.m=now.m-(n-now.n);
}
else
{
next.n=now.n+now.m;
next.m=;
}
next.s=now.s;
next.step=now.step+;
if(!vis[next.s][next.n][next.m])
{
vis[next.s][next.n][next.m]=;
Q.push(next);
}
}
else if(i==&&now.m!=&&now.s!=s)
{
if(now.s+now.m>s)
{
next.s=s;
next.m=now.m-(s-now.s);
}
else
{
next.s=now.s+now.m;
next.m=;
}
next.n=now.n;
next.step=now.step+;
if(!vis[next.s][next.n][next.m])
{
vis[next.s][next.n][next.m]=;
Q.push(next);
}
} }
}
}
return -;
}
int main()
{
while(scanf("%d%d%d",&s,&n,&m),s+n+m!=)
{
if(s%!=)
{
printf("NO\n");
}
else
{
memset(vis,,sizeof(vis));
int ans;
ans=bfs();
if(ans>=)
printf("%d\n",ans);
else
printf("NO\n");
}
}
return ;
}
简单点评
在上面的代码, 每次for循环都将枚举六种情况 ,1->2 , 1-》3,2-》3 ,2-》1,3-》1,3-》2 ,并且每种情况又要分为两种来讨论......
重复的部分太多了~
重复的部分太多了~
不够简洁,代码太长长了。
出错误了一不好找啊!
-------------------------------------------------------------------------------------------------------------------------------------我是分割线---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
起先我也是这么做的,后来我想了一个相对简单的优化办法:
进行结构体的嵌套 ,结构体cup 的 a[1]/a[2]/a[3]分别代表这 三个容器 ,其中结构体 cup中 up 代表一个容器的装水上限 ,now 代表现在的水量! 再用 结构体node 将cup和step 封装起来!
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring> //by @山枫叶纷飞
#include<cstdlib>
#include<cmath>
#include<string>
#include<set>
#include<queue>
using namespace std;
typedef long long ll;
double dinf=99999999.9, mm=1e-;
const int N=,inf=0x3f3f3f3f;
int s,n,m;
int vis[N][N][N];
struct cup
{
int up,now;
};
struct node
{
cup a[]; ///进行结构体的嵌套 ,a[1]/a[2]/a[3] 分别表示三个容器
int step;
};
int bfs( )
{
int i,j,k;
queue<node>Q;
node p,q;
p.a[].now=s;p.a[].up=s;
p.a[].now=;p.a[].up=n;
p.a[].now=;p.a[].up=m;
p.step=;
memset(vis,,sizeof(vis));vis[s][][]=;
Q.push(p);
while(Q.size()>)
{
p=Q.front(); ///从队列中取到的现在的状态
Q.pop();
if((p.a[].now==s/&&p.a[].now==s/) || (p.a[].now==s/&&p.a[].now==s/))///判断是否达到预期结果
return p.step;
if((p.a[].now==s/&&p.a[].now==s/))///判断是否达到预期结果(太长了,拆成了两段)
return p.step; for(i=;i<=;i++)
{
for(j=;j<=;j++)
{
if(i==j || p.a[i].now==||p.a[j].now==p.a[j].up)///简易排除
continue; q=p;///初始化,q 代表由p 延伸来的下一状态 int dif=p.a[j].up-p.a[j].now;///表示容器a[j]最多可添加水量
if(p.a[i].now>=dif)///若容器a[j]可被填满水
{
q.a[i].now=p.a[i].now-dif;
q.a[j].now=p.a[j].up;
}
else ///若容器a[j]不能装满水
{
q.a[i].now=;
q.a[j].now=p.a[i].now+p.a[j].now;
}
q.step=p.step+;
if(vis[q.a[].now][q.a[].now][q.a[].now]==)
{
vis[q.a[].now][q.a[].now][q.a[].now]=;
Q.push(q);
}
}
} }
return -;
}
int main()
{
while(scanf("%d%d%d",&s,&n,&m),s+n+m)
{
if(s%!=)///奇数一定无法均分成两份
printf("NO\n");
else
{
int k=bfs();
if(k==-)
printf("NO\n");
else
printf("%d\n",k);
}
} return ;
}
简单点评
两重for 循环,用a[i] 和a[j] 来模拟全部六种情况的倒水过程 ,省了超过100行的代码, 结构体的含义一目了然, 就是结构体名字写起来太长了!
还有要注意的是: { q=p;///初始化,q 代表由p 延伸来的下一状态}这段代码的位置很重要, 每次新的内层for循环都要记得将q重新初始化, 不然会造成意料之外的错误! 当时debug 到了 "debug人在天涯"!
---------------------------------------------------------我是分割线----------------------------------------------------------------------------------------------------------------------
其他思路
这个题目用数论也是可以做的! 近似玄学,,,感兴趣的话自行百度!
HDU-1495 非常可乐 (嵌套结构体-广搜 对比 一般广搜)的更多相关文章
- HDU 1495 非常可乐 (只是转了个弯的广搜题)
N - 非常可乐 =========================================================================================== ...
- abap中结构体嵌套结构体。
1: 结构体中嵌套结构体. *&---------------------------------------------------------------------* *& Re ...
- C语言 结构体(嵌套结构体--结构体数组)
//结构体--嵌套结构体和结构体数组 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> ...
- BFS(倒水问题) HDU 1495 非常可乐
题目传送门 /* BFS:倒水问题,当C是奇数时无解.一共有六种情况,只要条件符合就入队,我在当该状态vised时写了continue 结果找了半天才发现bug,泪流满面....(网上找份好看的题解都 ...
- matlab学习笔记12_2创建结构体数组,访问标量结构体,访问非标量结构体数组的属性,访问嵌套结构体中的数据,访问非标量结构体数组中多个元素的字段
一起来学matlab-matlab学习笔记12 12_2 结构体 创建结构体数组,访问标量结构体,访问非标量结构体数组的属性,访问嵌套结构体中的数据,访问非标量结构体数组中多个元素的字段 觉得有用的话 ...
- go变量、类的概念以及类的使用方式,嵌套结构体
go变量.类的概念以及类的使用方式,嵌套结构体 Go变量 go使用var声明变量,当声明变量时,这个变量对应的值总是会被初始化.这个值要么用指定的值初始化,要么用零值(即变 量类型的默认值)做初始化. ...
- hdu 1495 非常可乐 (广搜)
题目链接 Problem Description 大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为.因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶 ...
- hdu 1495 非常可乐 广搜
#include<iostream> #include<cstdio> #include<cstring> #include<queue> ][][]; ...
- HDU 1495 非常可乐(数论,BFS)
非常可乐 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submi ...
随机推荐
- NLTK学习笔记(八):文法--词关系研究的工具
[TOC] 对于一门语言来说,一句话有无限可能.问题是我们只能通过有限的程序来分析结构和含义.尝试将"语言"理解为:仅仅是所有合乎文法的句子的大集合.在这个思路的基础上,类似于 w ...
- 学习mysql语法--基础篇(一)
前 言 mysql mysql语法--本篇学习都是通过使用Navicat Premium(数据库管理工具),连接mysql数据. 本篇学习主要有两个部分: 一.创建用户,创建数据库,给 ...
- CentOS7安装docker 启动不了解决篇
[root@test ~]# yum update [root@test ~]# yum install docker [root@test ~]# service docker start Redi ...
- RabbitMQ安装与初始配置
[TOC] 本文只讨论linux下的Rabbitmq安装. Erlang安装 rabbitmq依赖于Erlang,需先安装,推荐安装rabbitmq/erlang-rpm: #clone源码 git ...
- chrome 浏览器最小字体为12px 的解决办法
http://banri.me/web/webkit-text-size-adjust.html 对div进行缩放 12*0,75 = 9 px -webkit-transform: scale(0. ...
- html之改变图片透明度而不改变文字的透明度--两种方法实现
图片与图片上的文字设置不同的透明度的两种方法: 第一种方法:背景图+定位+background: url(timg.jpg)no-repeat; <!DOCTYPE html> <h ...
- 给linux虚拟机添加Samba用户
Window系统连上我们的开发机Linux,自然需要在Samba里添加一个新用户. linux-06bq:/usr/local/services/samba/bin # ./smbpasswd -a ...
- 简单的视频采集demo
打算做个简单的聊天软件,其中一个我没做过的,就是视频采集. 在网上查了许久资料,终于搞清楚了dshow采集视频的流程 参考资料如下: https://msdn.microsoft.com/en-us/ ...
- 【Android Developers Training】 55. 序言:高效显示位图
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 最近学习java时的记录
1.java 的变量一共分为三种,类变量,局部变量,成员变量 类变量就是 加static修饰符的变量 2.java 的修饰符可分为两大类,一 可访问修饰符 protected private publ ...