[ 题解 ] 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行开始:
两套循环,变量i,j分别代表两边的桶。
每次组合开始前先把牛奶量整为1000,把读入的数据刷进当前列表;
tank+= tmp[1][j]-tmp[0][i];
这个表达式表示i,j两个桶交换对tank的变化;
交换两个列表中两个值,表示交换两个仓库中i,j这两个桶(的容量)。
proc2():
因为前一次来回已经改变了牛奶量,必须用一个新的变量t来表示。
同样两套循环,变量i,j分别代表两边的桶。
开始前保证当前牛奶量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,但其实两次交换中如果用了三个桶,效果与以上相同。
比如,这边有A,B两个桶,那边C,D;
假如第一次来回拿了A,相当于什么事也没做,第二次交换了A,C,如下:
A C => A C => C A
B D => B D => B D
一定要交换的话,先交换A,D,再交换D,C:
A C => D C => C D
B D => B A => B A
在代码中的表达式实现了 ( C – D ) – ( A – D ) = C – A。
所以这个情况不需要专门写出来。一定要模拟这个过程的话,只需在仓库二的列表中添加第11个桶,容量保持与这个桶相同;第二层循环改为11次,就可以了。