uva 10603(Fill, 隐式图搜索问题)
2015-09-06 20:48
225 查看
题目大意:
有三个杯子的容量分别为a, b, c, 最初只有第3个杯子装满了c升水,其他两个杯子为空。最少需要倒多少升水才能让某个水杯有d升,如果无法达到d升,找到某个杯子的水是d’升,其中d‘<d并且尽量接近d。(1< = a, b, c, d <= 200)。 要求输出最少的倒水量和目标水量(d或者d')。
题目分析:
首先,将三个杯子的水量看成是状态(v0, v1, v2); 那么我们可以描述出倒水过程中的状态变化:
这里我用结构体node 表示这个状态:
那么怎么表示状态的变化呢;
有了前面的介绍我们回到问题中,怎么求最少的倒水量和目标水量呢?
我们从起始的状态开始,枚举所有可能变化的状态,进行保存记录,不就可以了;
每个杯子的水量最多有201种可能,那么所有的状态不会超过201*201 = 40401; 是可以进行遍历的;
代码如下:
有三个杯子的容量分别为a, b, c, 最初只有第3个杯子装满了c升水,其他两个杯子为空。最少需要倒多少升水才能让某个水杯有d升,如果无法达到d升,找到某个杯子的水是d’升,其中d‘<d并且尽量接近d。(1< = a, b, c, d <= 200)。 要求输出最少的倒水量和目标水量(d或者d')。
题目分析:
首先,将三个杯子的水量看成是状态(v0, v1, v2); 那么我们可以描述出倒水过程中的状态变化:
这里我用结构体node 表示这个状态:
struct Node{ int w[3], dist; // w[i]表示第i个水杯中的水量; (i是从0开始计数) , dist表示目前为止最少的倒水量; };
那么怎么表示状态的变化呢;
</pre><pre name="code" class="cpp">//尝试将第i杯子中的水倒入j杯子中; Node v = u; // u为之前状态; for i = 0 to 2 for(j = 0 to 2) if(j == i) continue; //不能自己给自己倒水; int water = min(v.w[i], cap[j]-v.w[j]); //cap[i]表示i杯子的容积; water表示可以倒的水量; v.w[i] -= water; v.w[j] += water;
有了前面的介绍我们回到问题中,怎么求最少的倒水量和目标水量呢?
我们从起始的状态开始,枚举所有可能变化的状态,进行保存记录,不就可以了;
每个杯子的水量最多有201种可能,那么所有的状态不会超过201*201 = 40401; 是可以进行遍历的;
代码如下:
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; const int maxn = 200+5; int cap[3], d; struct Node{ int w[3], dist; }; int ans[maxn], vis[maxn][maxn]; void Init(){ memset(vis, 0, sizeof(vis)); memset(ans, -1, sizeof(ans)); } void update_ans(Node &s){ for(int i = 0; i < 3; ++i){ int d = s.w[i]; if(ans[d] < 0 || s.dist < ans[d]) ans[d] = s.dist; } } void bfs(){ queue<Node> q; Node u, v; u.w[0] = u.w[1] = 0; u.w[2] = cap[2]; u.dist = 0; vis[0][0] = 1; q.push(u); while(!q.empty()){ u = q.front(); q.pop(); update_ans(u); for(int i = 0; i < 3; ++i) for(int j = 0; j < 3; ++j){ if(i == j) continue; v = u; int water = min(u.w[i], cap[j]-u.w[j]); v.w[i] -= water; v.w[j] += water; v.dist += water; int ok = 0; for(int i = 0; i < 3; ++i){ // 一定注意这里, 不是访问过就不能访问了,如果倒水总量小于之前的,依旧要访问; if(v.dist < ans[v.w[i]]) ok = 1; } if(!vis[v.w[0]][v.w[1]] || ok){ vis[v.w[0]][v.w[1]] = 1; q.push(v); } } } } int main() { int T; scanf("%d", &T); while(T--){ scanf("%d%d%d%d", &cap[0], &cap[1], &cap[2], &d); Init(); bfs(); for(int i = d; i >= 0; --i) if(ans[i] >= 0){ //之前写成>找了很长时间的bug, 注意这些细节; printf("%d %d\n", ans[i], i); break; } } return 0; }
相关文章推荐
- 趣味C++
- 理解虚函数表
- 用C语言实现多态
- 工厂模式
- java设计原则
- 趣味C++
- 磁盘管理及文件系统管理
- 黑马程序员之反射
- 关于CSS浮动与绝对定位的个人感悟,看完这篇文章能得到很多相关问题的解释
- Django开发教程 第一节 HelloWorld
- 基类私有虚函数可被派生类重写
- Testlink软件测试项目管理之流程图与权限划分
- 61条面向对象设计的经验原则
- Linux 磁盘管理命令fdisk.df.du.mount等的介绍
- bash 环境变量
- STL—利用pair和vector对有序对类型排序
- HashMap&HashTable
- zoj 2091 Mean of Subsequence(奇怪的贪心)
- Google Accounts,OpenID,OAuth
- HDU-4849 Wow! Such City! (单源最短路)