题意: 给你三个杯子。 a,b,c. 且 a=b+c;
问你能不能将a里面的水平分。
能的话求出最少次数。
不能输出NO ;
很明显奇数是一定gg的。
直接暴力bfs来一发。每次可走的路可分为6条。
a->b
a->c
b->a
......
就过了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=101+10;
int vis[maxn][maxn][maxn];
int cup[5];
struct Cup{
int gle[5],step;
}c;
int pour(int a,int b){
int sum=c.gle[a]+c.gle[b];
if(sum>=cup[b]) c.gle[b]=cup[b];
else c.gle[b]=sum;
c.gle[a]=sum-c.gle[b];
}
int bfs(){
queue<Cup>que;
Cup u,e;
vis[cup[0]][0][0]=1;
u.gle[0]=cup[0],u.gle[1]=0,u.gle[2]=0,u.step=0;
que.push(u);
while(!que.empty()){
e=que.front();//printf("%d %d %d %d\n",e.gle[0],e.gle[1],e.gle[2],e.step);
que.pop();
if(e.gle[0]==e.gle[1]&&e.gle[2]==0) return e.step;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(i==j) continue;
c=e;
if(c.gle[i]==0) continue;
pour(i,j);
//for(int k=0;k<3;k++) if(c.gle[k]<0) continue;
if(!vis[c.gle[0]][c.gle[1]][c.gle[2]]){
c.step++;
que.push(c);
vis[c.gle[0]][c.gle[1]][c.gle[2]]=1;
}
}
}
}
return 0;
}
int main(){
while(scanf("%d%d%d",&cup[0],&cup[1],&cup[2])&&(cup[0]+cup[1]+cup[2])){
if(cup[0]&1) {
printf("NO\n"); continue;
}
if(cup[1]<cup[2]) swap(cup[1],cup[2]);
memset(vis,0,sizeof(vis));
int ans=bfs();
if(ans) printf("%d\n",ans);
else printf("NO\n");
}
return 0;
}
另外还有数学规律:
设3个杯子a,b,c;
可以把问题转化成有两个杯子,通过这两个杯子加水倒水而达到水二分的目的。
可以设 b倒水x次
c倒水y次
x,y为正时,表示到出,为负时表示倒入。
可列方程
bx+cy=(b+c)/2;
求|x|+|y| 最小值。 则对b,c取最小公倍数。
设g=gcd(b,c);
d=b/g;
e=c/g;
so:: dx+ey=(d+e)/2;
简单凑一下就可得出一组解。x=(1+d)/2;
y=(1-e)/2;
显然x,y 一正一负。
|x|+|y|= |x-y|=(d+e)/2;
即为所求。减去本身状态,即为所求。
#include<bits/stdc++.h>
using namespace std;
const int maxn=101+10;
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int main(){
int cup[5];
while(scanf("%d%d%d",&cup[0],&cup[1],&cup[2])&&(cup[0]+cup[1]+cup[2])){
int s=gcd(cup[1],cup[2]);
cup[0]/=s;
if(cup[0]&1) printf("NO\n");
else printf("%d\n",cup[0]-1);
}
return 0;
}