HDU 1495 非常可乐 数论方法
Problem Description
大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为。因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多。但seeyou的手中只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升 (正好装满一瓶) ,它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。聪明的ACMER你们说他们能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出"NO"。
Input
三个整数 : S 可乐的体积 , N 和 M是两个杯子的容量,以"0 0 0"结束。
Output
如果能平分的话请输出最少要倒的次数,否则输出"NO"。
Sample Input
7 4 3
4 1 3
0 0 0
Sample Output
NO
3
Author
seeyou
Source
“2006校园文化活动月”之“校庆杯”大学生程序设计竞赛暨杭州电子科技大学第四届大学生程序设计竞赛
Analysis
因为瓶子是没有刻度的,所以说N 和 M是基本单位(并非最小单位),即所有可能的结果都是基于N 和 M。比如说,假设N > M,可以通过S -> N,N -> M来得到N—M,重复类似操作,得到的结果可以一般地表示为xN + yM,a 和 b为整数,x 和 y表示对N瓶和M瓶的操作数(两者不含重复部分)。
Solution
Code
#include <cstdio>
#include <algorithm>
int main()
{
int s, n, m;
while(scanf("%d%d%d", &s, &n, &m)==3 && s+n+m){
s /= std :: __gcd(n, m);
if(s&1) printf("NO\n");
else printf("%d\n", s-1);
}
return 0;
}
PS.
0.数论方法吹爆,核心代码不过五行!!!(自然不是我这种蒟蒻想出来的。)
1.用到的数论知识:裴蜀定理,二元一次不定方程的通解。
2.抄来的DFS打印具体方案(大,中,小3个杯子的容量分别为a,b,c,最初只有大杯子装满水,其他两个杯子为空。给出最少需要步数的方案让某一个杯子中的水有x升)以及两组辅助理解的数据
/*
因为给出条件后3个杯子中水的总量同时确定,所以可以减少用于记录的数组维数。使用递归的方法遍历可能经过的所有路径并记录可到达的最短步数
*/
#include<iostream>
#include<string.h>
using namespace std;
struct node{
int par[2];
//存储到达该节点处上一个节点的位置
int value;
//到该节点为止转移次数
};
int a,b,c;
struct node path[1000][1000];
// 仅存储两个杯子的水量,用以节省空间
void fun(int cura,int curb,int curc){
//转移算法,使用递归方法
int cura1,curb1,curc1;
if(cura!=a){
if((cura+curb)>a){
cura1=a;curb1=cura+curb-cura1;curc1=curc;
if(path[curb1][curc1].value==-1||(path[curb1][curc1].value>path[curb][curc].value+1)){
path[curb1][curc1].par[0]=curb;path[curb1][curc1].par[1]=curc;
path[curb1][curc1].value=path[curb][curc].value+1;
fun(cura1,curb1,curc1);
}
}
else{
cura1=cura+curb;curb1=0;curc1=curc;
if(path[curb1][curc1].value==-1||(path[curb1][curc1].value>path[curb][curc].value+1)){
path[curb1][curc1].par[0]=curb;path[curb1][curc1].par[1]=curc;
path[curb1][curc1].value=path[curb][curc].value+1;
fun(cura1,curb1,curc1);
}
}
if((cura+curc)>a){
cura1=a;curb1=curb;curc1=cura+curc-cura1;
if(path[curb1][curc1].value==-1||(path[curb1][curc1].value>path[curb][curc].value+1)){
path[curb1][curc1].par[0]=curb;path[curb1][curc1].par[1]=curc;
path[curb1][curc1].value=path[curb][curc].value+1;
fun(cura1,curb1,curc1);
}
}
else{
cura1=cura+curc;curb1=curb;curc1=0;
if(path[curb1][curc1].value==-1||(path[curb1][curc1].value>path[curb][curc].value+1)){
path[curb1][curc1].par[0]=curb;path[curb1][curc1].par[1]=curc;
path[curb1][curc1].value=path[curb][curc].value+1;
fun(cura1,curb1,curc1);
}
}
}
if(curb!=b){
if(cura+curb>b){
cura1=cura+curb-b;curb1=b;curc1=curc;
if(path[curb1][curc1].value==-1||(path[curb1][curc1].value>path[curb][curc].value+1)){
path[curb1][curc1].par[0]=curb;path[curb1][curc1].par[1]=curc;
path[curb1][curc1].value=path[curb][curc].value+1;
fun(cura1,curb1,curc1);
}
}
else{
cura1=0;curb1=cura+curb;curc1=curc;
if(path[curb1][curc1].value==-1||(path[curb1][curc1].value>path[curb][curc].value+1)){
path[curb1][curc1].par[0]=curb;path[curb1][curc1].par[1]=curc;
path[curb1][curc1].value=path[curb][curc].value+1;
fun(cura1,curb1,curc1);
}
}
if(cura+curc>c){
cura1=cura+curc-c;curb1=curb;curc1=c;
if(path[curb1][curc1].value==-1||(path[curb1][curc1].value>path[curb][curc].value+1)){
path[curb1][curc1].par[0]=curb;path[curb1][curc1].par[1]=curc;
path[curb1][curc1].value=path[curb][curc].value+1;
fun(cura1,curb1,curc1);
}
}
else{
cura1=0;curb1=curb;curc1=cura+curc;
if(path[curb1][curc1].value==-1||(path[curb1][curc1].value>path[curb][curc].value+1)){
path[curb1][curc1].par[0]=curb;path[curb1][curc1].par[1]=curc;
path[curb1][curc1].value=path[curb][curc].value+1;
fun(cura1,curb1,curc1);
}
}
}
if(curc!=c){
if((cura+curc)>c){
cura1=cura+curb-c;curb1=curb;curc1=c;
if(path[curb1][curc1].value==-1||(path[curb1][curc1].value>path[curb][curc].value+1)){
path[curb1][curc1].par[0]=curb;path[curb1][curc1].par[1]=curc;
path[curb1][curc1].value=path[curb][curc].value+1;
fun(cura1,curb1,curc1);
}
}
else{
cura1=0;curb1=curb;curc1=curc+cura;
if(path[curb1][curc1].value==-1||(path[curb1][curc1].value>path[curb][curc].value+1)){
path[curb1][curc1].par[0]=curb;path[curb1][curc1].par[1]=curc;
path[curb1][curc1].value=path[curb][curc].value+1;
fun(cura1,curb1,curc1);
}
}
if((curb+curc)>c){
cura1=cura;curb1=curb+curc-c;curc1=c;
if(path[curb1][curc1].value==-1||(path[curb1][curc1].value>path[curb][curc].value+1)){
path[curb1][curc1].par[0]=curb;path[curb1][curc1].par[1]=curc;
path[curb1][curc1].value=path[curb][curc].value+1;
fun(cura1,curb1,curc1);
}
}
else{
cura1=cura;curb1=0;curc1=curc+curb;
if(path[curb1][curc1].value==-1||(path[curb1][curc1].value>path[curb][curc].value+1)){
path[curb1][curc1].par[0]=curb;path[curb1][curc1].par[1]=curc;
path[curb1][curc1].value=path[curb][curc].value+1;
fun(cura1,curb1,curc1);
}
}
}
}
//打印出转移路线
void print(struct node a1){
if(a1.par[0]==-1&&a1.par[1]==-1);//......
else{
print(path[a1.par[0]][a1.par[1]]);
cout<<a-a1.par[0]-a1.par[1]<<'\t'<<a1.par[0]<<'\t'<<a1.par[1]<<endl;
}
}
int main(){
int x,min,k,mk;struct node minb;
while(cin>>a>>b>>c){
for(int i=0;i<1000;i++)
for(int j=0;j<1000;j++){
path[i][j].par[0]=path[i][j].par[1]=path[i][j].value=-1;
}
path[0][0].value=0;
fun(a,0,0);
//遍历所有转移路线
cin>>x;
{
min=1000,minb;
for(k=0;k<=a-x;k++){
if(path[k][a-x-k].value!=-1&&path[k][a-x-k].value<min){
min=path[k][a-x-k].value;
minb=path[k][a-x-k];
mk=k;
}
}
//在转移路线中查找最短路径
if(min==1000)
cout<<"Not found"<<endl;
else{
cout<<min<<endl;
print(minb);
cout<<x<<'\t'<<mk<<'\t'<<a-x-mk<<endl;
}
}
}
return 0;
}
/*
8 5 3
4
7
8 0 0
3 5 0
3 2 3
6 2 0
6 0 2
1 5 2
1 4 3
4 4 0
30 27 3
15
9
30 0 0
3 27 0
3 24 3
6 24 0
6 21 3
9 21 0
9 18 3
12 18 0
12 15 3
15 15 0
*/