Pouring water

#include<iostream>
#include<queue>
#include<string.h>
#define MAX 10000000
using namespace std;
int f[201][201][201];//用来存放到达某个状态所需倒的最少水量
short inQ[201][201][201];//用来标记某个状态是否在队列中

int main()
{
    queue<int> q;
    short s[3], d;
    int T;
    cin>>T;
    while(T--){//将三个量筒的最大储水量用s[]数组存放
        cin>>s[0]>>s[1]>>s[2]>>d;
        int res0 = MAX, res1 = -1;//开始时将最少所需倒的水量设置为最大值,将最终要求得的d的值设置为很小
        memset(inQ, 0, sizeof(inQ));//将数组inQ的值都进行初始化
        for(int i = 0; i < 200; i++)
        for(int j = 0; j < 200; j++)
        for(int k = 0; k < 200; k++)
            f[i][j][k] = MAX;//将f[][][]的值进行初始化
        f[0][0][s[2]] = 0;//表示a和b中无水,c中有水

        while(!q.empty())  q.pop();
        q.push(s[2]); inQ[0][0][s[2]] = 1; //将初始状态的值放到队列当中
        while(!q.empty()){
            int to = q.front();
            short u[] = {to>>16, ((to>>8) & ((1<<8) - 1)), to&((1<<8) - 1)};//将从队列中取出的数据分离出来

            for(int i = 0; i < 3; i++){//判断能否对结果进行更新
                if((u[i] <= d && u[i] > res1) || (u[i] == res1 && (f[u[0]][u[1]][u[2]] < res0))){
                    res0 = f[u[0]][u[1]][u[2]];
                    res1 = u[i];
                }//if
            }//for

            short v[3];
            for(int i = 0; i < 3; i++){//将量筒i中的水倒入j中
                for(int j = 0; j < 3; j++){
                    if(i != j){
                        short to = min(u[i], short(s[j] - u[j]));
                        if(to == 0) continue;//若i为空,或者j已经满了就不能进行操作了
                        v[i] = u[i] - to;//从i中将to量的水到出
                        v[j] = u[j] + to;//将to量的水放到j中
                        v[3-i-j] = u[3-i-j];
                        if(f[v[0]][v[1]][v[2]] > f[u[0]][u[1]][u[2]]+to) {//判断是否能够进行更新
                            f[v[0]][v[1]][v[2]] = f[u[0]][u[1]][u[2]]+to;
                            if(!inQ[v[0]][v[1]][v[2]]){//只有能够进行更新并且该状态不在队列中才将该状态放到队列中
                                inQ[v[0]][v[1]][v[2]] = 1;
                                q.push((v[0]<<16)|(v[1]<<8)|v[2]);
                            }
                        }
                    }
                }
            }
            q.pop();
        }//while

        cout<<res0<<' '<<res1<<endl;
    }//while

    return 0;
}
/*
100
101 135 68 42
0 0
159 79 125 170
0 125
146 106 65 163
0 65
92 162 28 82
0 28
37 28 143 196
0 143
154 103 5 192
0 5
117 22 183 93
2249 93
127 48 96 119
0 96
113 70 139 172
0 139
95 36 100 68
36 64
134 123 12 104
0 12
112 142 65 74
0 65
45 148 69 54
45 45
60 38 158 63
1234 62
179 130 142 124
130 12
43 191 36 117
0 36
143 41 107 89
164 82
6 47 49 65
0 49
151 171 130 91
0 0
149 194 102 7
0 0
155 85 24 30
0 24
177 167 41 157
0 41
40 145 109 132
0 109
139 138 124 27
0 0
142 130 83 119
0 83
59 40 116 34
478 34
107 178 131 105
107 24
146 22 187 74
586 74
30 71 73 125
0 73
113 98 174 178
0 174
37 162 91 187
0 91
175 56 168 156
56 112
151 151 53 32
0 0
31 167 125 142
0 125
138 8 192 108
604 108
184 154 88 58
0 0
159 10 110 146
0 110
147 23 189 22
2138 22
169 14 31 107
0 31
56 163 192 101
275 85
138 25 160 11
275 10
42 196 84 149
0 84
37 92 151 3
1567 3
22 197 21 175
0 21
85 69 200 149
6936 149
200 54 135 82
54 81
189 101 139 19
0 0
94 129 68 128
0 68
22 8 84 49
22 22
115 14 18 111
0 18
52 136 17 110
0 17
157 120 50 1
0 0
9 25 104 199
0 104
103 190 10 45
0 10
144 94 86 196
0 86
104 115 188 124
1938 122
19 59 1 49
0 1
82 199 197 181
328 164
158 10 199 190
10 189
93 139 23 73
0 23
58 191 180 39
290 6
89 16 192 159
1919 159
35 3 112 157
0 112
47 129 56 73
0 56
34 76 87 163
0 87
17 45 143 70
45 45
52 123 199 82
4979 82
77 158 100 22
0 0
113 76 190 93
5569 93
70 4 111 1
0 0
190 2 89 62
124 62
186 3 24 56
0 24
27 89 86 183
0 86
133 33 158 18
2919 18
190 122 155 170
0 155
93 169 130 177
0 130
150 35 156 26
245 16
61 146 113 42
0 0
24 140 154 119
1308 118
130 88 197 80
130 67
150 67 38 150
0 38
17 98 196 194
2348 194
83 89 106 87
83 83
102 115 135 56
102 33
64 187 72 117
0 72
54 186 156 114
216 108
146 33 9 113
0 9
159 122 157 114
122 35
145 82 183 47
145 38
162 130 23 197
0 23
67 174 51 136
0 51
40 93 60 45
40 40
111 155 25 54
0 25
114 187 50 146
0 50
19 169 23 75
0 23
192 159 106 188
0 106
15 78 26 3
0 0
75 135 25 115
0 25
71 34 160 173
0 160
178 119 98 88
0 0

Process returned 0 (0x0)   execution time : 28.524 s
Press any key to continue.
*/

这道题目是3.16日周赛的题目,原题貌似是Uva的。题目意思是:

Prob IV. Pouring Water

There are three jugs with a volume of a, b and c liters. The first and the second jug are initially empty, while the third is completely filled with water. It is allowed to pour water from one jug into another until either the first one is empty or the second one is full.

You are to write a program that computes the least total amount of water that needs to be poured; so that at least one of the jugs contains exactlyd liters of water. If it is not possible to measure d liters this way your program should find a smaller amount of waterd' < d which is closest to d and for which d' liters could be produced. Whend' is found, your program should compute the least total amount of poured water needed to produced' liters in at least one of the jugs.

Input

The first line of input contains the number of test cases T. In the nextT lines, T test cases follow. Each case is given in one line of input containing four space separated integersa, b, c and d.

Output

The output consists of two integers separated by a single space. The first integer equals the least total amount (the sum of all waters you pour from one jug to another) of poured water. The second integer equalsd, if d liters of water could be produced by such transformations, or equals the closest smaller valued' that your program has found.

Restraints

0<a,b,c,d<=200

Sample

InputOutput
2
2 3 4 2
96 97 199 62
2 2
9859 62
这道题目主要的算法就是用到了SPFA,解释一下我的代码吧。(其实我是看了标程之后自己重新写的,写完之后找错找了很久,不过上面的代码是编译无误的,代码的下面我放了100组测试数据,每一组INT后面的一行有它对应的OUT)。


定义的东西解释:1.首先用到了STL中的queue;2.定义了int f[201][201][201]数组用来表示3个量筒中的水达到某个状态时所需要倒的水的最少量(和res0相对应),定义了short inQ[201][201][201]用来标记某个状态是否在队列中。3.T表示测试数据的组数,数组short[3]中分别存放的是a, b, c的值(也就是量筒的最大容量)。4.res0表示所需倒水的最小量,res1表示其中某个量筒中的水达到题目要求的量。


while(!q.empty()){}循环的内容:这个循环中的内容是重点!1.首先将初始的状态放入到队列中,大家应该注意到开始我定义的队列中的数的数据类型是int型的,(也就是说一次只能存放一个int型的数)但是要表示状态需要将三个量筒的状态都包含在其中。这里用到了一个方法就是将三个short类型的数压缩到一个int型的数中,如q.push((v[0]<<16) | (v[1]<<8) | v[2]);这里用int型数据的后0-8位存放第三个量筒中的水量,9-16位存放第二个量筒中的水量,17-24位存放第一个量筒中的水量。之前我做压缩操作的时候写成了q.push((v[0]<<16) & (v[1]<<8) & v[2]);导致我得到的结果一直错误,所以大家注意一下这里。当需要分别得到每个量筒中存水量这个状态的时候就需要做相应的解压操作,如short u[] = {to>>16, ((to>>8) & ((1<<8) - 1)), to&((1<<8) - 1)};//将从队列中取出的数据分离出来。2.还有一个我之前犯的错误就是直接将量筒的最大容量a, b, c当作初始状态,而实际上其初始状态是0, 0, c这个量;  3.然后将初始状态放入到队列中,用SPFA算法进行求所需倒水的最少量的求解,(SPFA算法可以参考我之前写的SPFA博文)。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值