[ 题解 ] G. Back and Forth (待更名)

http://codeforces.com/group/NVaJtLaLjS/contest/238166/problem/G

题意:

星期一两个仓库都有10个桶与1000加仑牛奶,桶的容量不一。

星期二John会从仓库一随机拿一桶牛奶去仓库二:

比如拿了一个容量为5的桶,那么仓库一减少5加仑牛奶,仓库二增加5加仑。并且这个桶会留在仓库二;

星期三又会从仓库二随机拿一桶牛奶去仓库一,同样把桶留下;

星期四同星期二;

星期五同星期三。


最后问仓库一的牛奶量有多少种可能。


示例:

Input

1 1 1 1 1 1 1 1 1 2
5 5 5 5 5 5 5 5 5 5

Output 

5 

 

本来我以为要用结构体队列来BFS的,突然发现他一共就来回了两次。

这意味着什么?意味着他其实在两个仓库间交换牛奶桶两次。


比如从仓库一带1加仑去仓库二,再带5加仑回来,仓库一牛奶+(5-1)

第二次同理,只不过因为交换了一对桶,要更新桶的容量列表。如:

1 1 1 1 1 5 1 1 1 2
5 5 5 1 5 5 5 5 5 5

 

两边有10个桶,桶两两之间的组合有100种。更新后再交换一次,组合100种。10000次暴力组合。


每次组合后会得出仓库一的牛奶量,用一个数组存这些数就可以了。


tank:仓库一的牛奶量;

buckets[2][10]:读入的两个仓库中各桶的容量;

tmp[2][10]:目前两个仓库中各桶的容量;

answer[10000]:顾名思义存答案啦。


proc2():只是为了易读而把一些过程写成一个函数。请先读main()


33行开始:

两套循环,变量ij分别代表两边的桶。


每次组合开始前先把牛奶量整为1000,把读入的数据刷进当前列表;

tank+= tmp[1][j]-tmp[0][i];

这个表达式表示ij两个桶交换对tank的变化;

交换两个列表中两个值,表示交换两个仓库中ij这两个桶(的容量)。


proc2()

因为前一次来回已经改变了牛奶量,必须用一个新的变量t来表示。

同样两套循环,变量ij分别代表两边的桶。


开始前保证当前牛奶量t是上一过程得到的。

同样的表达式;

记下最终牛奶量。答案已存在就离开。


最后统计答案数量就行了。


代码如下:

 

 1 #include <stdio.h>
 2 #include <string.h>
 3 
 4 int tank=1000;
 5 int buckets[2][10]={0};
 6 int tmp[2][10]={0};
 7 int answer[10000]={0};
 8 int proc2()
 9 {
10     int t;
11     for(int i=0;i<10;i++)
12     {
13         for(int j=0;j<10;j++)
14         {
15             t=tank;
16             t+= tmp[1][j]-tmp[0][i];
17             int q=0;
18             for(;answer[q];q++)
19             {
20                 if( t==answer[q] )break;
21             }
22             answer[q]=t;
23         }
24     }
25     
26     return 0;
27 }
28 
29 int main()
30 {
31     for(int i=0;i<20;i++)
32         scanf("%d",buckets[0]+i);
33     for(int i=0;i<10;i++)
34     {
35         for(int j=0;j<10;j++)
36         {
37             memcpy(tmp,buckets,20*sizeof(int));
38             tank=1000;
39             tank+= tmp[1][j]-tmp[0][i];
40             int t=tmp[1][j];
41                 tmp[1][j]=tmp[0][i];
42                 tmp[0][i]=t;
43             proc2();
44         }
45     }
46     int i=0;
47     for(;answer[i];i++)
48     {
49     //    printf("%d,",answer[i]);
50     }
51     printf("%d\n",i);
52     return 0;
53 }

 

 

有人会提出这样的问题:这个代码这样写会导致两次来回都会交换两个桶;

如果第一次来回拿了同一个桶,第二次拿了不同的桶,是否会导致结果错误?


不会。表面上是有这样一个bug,但其实两次交换中如果用了三个桶,效果与以上相同。


比如,这边有AB两个桶,那边CD


假如第一次来回拿了A,相当于什么事也没做,第二次交换了AC,如下:

A        C    =>    A        C    =>    C        A
B        D    =>    B        D    =>    B        D

一定要交换的话,先交换AD,再交换DC 

A        C    =>    D        C    =>    C        D
B        D    =>    B        A    =>    B        A

 

在代码中的表达式实现了 ( C – D ) – ( A – D ) = C – A


所以这个情况不需要专门写出来。一定要模拟这个过程的话,只需在仓库二的列表中添加第11个桶,容量保持与这个桶相同;第二层循环改为11次,就可以了。

 

posted @ 2019-02-17 01:34  Kaidora  阅读(258)  评论(0编辑  收藏  举报