foj1081等分液体

来源:互联网 发布:不亦…乎 编辑:程序博客网 时间:2024/06/11 17:01

http://acm.fzu.edu.cn/status.php?pid=1081

今天在看贪心,看了一阵子去翻了下各个公司的笔试算法题,又看到那道分液体的题,想起来foj上这道,bfs的方法不会,索性去推导,推了一会儿才发现满简单的。L=m+n,m》n。

比如输入130=85+45,有65=85-20=45-25=85-60=85-45-15=45-30=85-55=85-45-10=45-35=85-50=85-45-5=45-40=85-45,然后从后面往前操作就可以了,这个过程是唯一的最小操作步骤的解,比如65=85-20,还可写成65=130-65=45+20,可是这2种形式都没意义,130-65本身就利用结果65了,45+20表示的是在小容器加入20的液体也是没意义的,因为会溢出,换句话说操作的最后一步一定是从85的容器中倒出20的液体,我们能组合出20的体积问题就解决了,这个20的液体又必须且只能通过45的容器来得到,如果利用85的那就写成20=85-65了明显回去了,这个过程就好比2个人背靠背坐着,相互借力维持平衡。这样有解的情况我们就解决了,那么无解的情况呢,我们看个例子。

90=60+30,45=60-15=30-15=60-45,是的很容易就发现了,回推的过程会出现循环,这个例子还好循环的数字就是第一个,有些例子是从中间开始循环的,我们如果记录下所有的过程又会有些麻烦,其实这个可以用鸽笼原理来解决,我们每次推导的数字都是小于m的,如果循环(推导)的步数超过m那么就一定出现循环了,即无解的情况,写程序的时候我们发现m是需要变化的,那也不妨放大至L就是了。其实这题无解的时候是可以判断出来的。这里提个定理:如果 (a,b)=1,那么一定存在x,y,使得ax+by=1。

应用到我们这个题,上式进一步写成 anx+bny=n*1;意思就是对于给定的m,n我们能组合出的体积一定是他们公约数的整数倍,对于(60,30)=30,我们只能组合出30n形式的体积,45当然不行。

附上代码吧:

#include<iostream>using namespace std;int main(){int t[2],n,i,k,Case,m;cin>>Case;while(Case--)  //样例数{cin>>n>>t[0]>>t[1];if(n%2!=0){cout<<"no"<<endl;continue;}else{m=n/2;k=0;i=0;  //k:循环访问控制,i: 操作次数while(i<=150){m=t[k]-m;i++;k=(k+1)%2;while(m>=t[k])m-=t[k],i++;if(m==0)break;}if(i<150)cout<<i+i-1<<endl;elsecout<<"no"<<endl;}}return 0;}
4.19:今天上午讨论课,师兄论文讲得天书一样,想到这个程序提交时看到最短的代码不到300B,应该有更简单的方法:设(m,n)=c,那么有ans=L/c-1,这个不是凭空想象的,可以证明,有点罗嗦,这里就不写了。写完后代码降了一半多O(∩_∩)O~。