题目链接:
非常可乐
大意:
有 m,n,s 三个不同容积的杯子,一开始 m,n 瓶为空,s 瓶是装满的,问在多少步内能平分成两个 s/2 的情况。 若不能,输出《NO》
思路:
一开始想到了gcd写法,还没想好,再补。
不会的话只能用 BFS 慢慢写了,题目卡时间有点过分,写残一点就会T,注意细节优化,以及不必要的空间申请,不必要的修改。
Node结点储存 三个杯子的状态以及当前操作数。
具体实现:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair pii;
#define mem(s,t) memset(s,t,sizeof(s))
#define D(v) cout<<#v<<" "<
#define inf 0x3f3f3f3f
#define pb push_back
//#define LOCAL
const int mod=1e9+7;
const int MAXN =1e5+10;
int m,n,s;
struct node {
int a,b,c,dist;
};
bool vis[105][105][105];
int bfs() {
queue q;
node u;
u.a=0,u.b=0,u.c=s,u.dist=0;
q.push(u);
mem(vis,0);
vis[0][0][s]=1;
while(!q.empty()) {
node t=q.front();
node x;
q.pop();
if(t.a==s/2 && t.c==s/2)
return t.dist;
//c->a
if(t.c && t.a!=m) {
if(t.a+t.c<=m) {
x.a=t.a+t.c;
x.c=0;
} else {
x.a=m;
x.c=t.a+t.c-m;
}
x.b=t.b;
if(!vis[x.a][x.b][x.c]) {
x.dist=t.dist+1;
q.push(x);
vis[x.a][x.b][x.c]=1;
}
}
//c->b
if(t.c && t.b!=n) {
if(t.b+t.c<=n) {
x.b=t.b+t.c;
x.c=0;
} else {
x.b=n;
x.c=t.b+t.c-n;
}
x.a=t.a;
if(!vis[x.a][x.b][x.c]) {
x.dist=t.dist+1;
q.push(x);
vis[x.a][x.b][x.c]=1;
}
}
//a->b
if(t.a && t.b!=n) {
if(t.a+t.b<=n) {
x.a=0;
x.b=t.a+t.b;
} else {
x.a=t.a+t.b-n;
x.b=n;
}
x.c=t.c;
if(!vis[x.a][x.b][x.c]) {
x.dist=t.dist+1;
q.push(x);
vis[x.a][x.b][x.c]=1;
}
}
//a->c
if(t.a && t.c!=s) {
x.a=0;
x.b=t.b;
x.c=t.a+t.c;
if(!vis[x.a][x.b][x.c]) {
x.dist=t.dist+1;
q.push(x);
vis[x.a][x.b][x.c]=1;
}
}
//b->a
if(t.b && t.a!=m) {
if(t.a+t.b<=m) {
x.a=t.a+t.b;
x.b=0;
} else {
x.a=m;
x.b=t.a+t.b-m;
}
x.c=t.c;
if(!vis[x.a][x.b][x.c]) {
x.dist=t.dist+1;
q.push(x);
vis[x.a][x.b][x.c]=1;
}
}
//b->c
if(t.b && t.c!=s) {
x.a=t.a;
x.b=0;
x.c=t.b+t.c;
if(!vis[x.a][x.b][x.c]) {
x.dist=t.dist+1;
q.push(x);
vis[x.a][x.b][x.c]=1;
}
}
}
return 0;
}
int main() {
while(~scanf("%d%d%d",&s,&m,&n) && m+n+s) {
if(mswap (m,n);
if(s&1 ||(s/2>m)) {
puts("NO");
continue;
}
int ans=bfs();
if(ans) printf("%d\n",ans);
else puts("NO");
}
return 0;
}
根据大佬的写法启发,修改了已很多代码操作= =
http://blog.csdn.net/zwj1452267376/article/details/49559913
优化后:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
#define mem(s,t) memset(s,t,sizeof(s))
#define D(v) cout<<#v<<" "<
#define inf 0x3f3f3f3f
#define pb push_back
//#define LOCAL
const int mod=1e9+7;
const int MAXN =1e5+10;
int cap[5];
struct node {
int v[5],dist;
};
bool vis[105][105][105];
void pour(node &x,int i,int j){//i->j
if(x.v[i]+x.v[j]<=cap[j]){
x.v[j]+=x.v[i];
x.v[i]=0;
}
else {
x.v[i]=x.v[i]+x.v[j]-cap[j];
x.v[j]=cap[j];
}
}
int bfs() {
queue q;
node u;
u.v[1]=0,u.v[2]=0,u.v[3]=cap[3],u.dist=0;
q.push(u);
mem(vis,0);
vis[0][0][cap[3]]=1;
while(!q.empty()) {
node t=q.front();
node x;
q.pop();
if(t.v[1]==cap[3]/2 && t.v[3]==cap[3]/2)
return t.dist;
for(int i=1;i<4;i++){
for(int j=1;j<4;j++){
if(i!=j){
x=t;
pour(x,i,j);
//cout<
if(!vis[x.v[1]][x.v[2]][x.v[3]]){
vis[x.v[1]][x.v[2]][x.v[3]]=1;
x.dist++;
q.push(x);
}
}
}
}
}
return 0;
}
int main() {
while(~scanf("%d%d%d",&cap[3],&cap[1],&cap[2]) && cap[1]+cap[2]+cap[3]) {
if(cap[1]2 ]) swap(cap[1],cap[2]);
if(cap[3]&1 ||(cap[3]/2>cap[1])) {
puts("NO");
continue;
}
int ans=bfs();
if(ans) printf("%d\n",ans);
else puts("NO");
}
return 0;
}
========================================================
数论解法:
想到了个大概 然后没想清楚,看到一篇博客
http://blog.csdn.net/V5ZSQ/article/details/52097459
注意题目条件:
S==M+N
由于 x,y 必然一正一负,是可以确定最终表达式的。
#include
using namespace std;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int main(){
int m,n,s;
while(cin>>s>>m>>n && m+n+s){
int ans=s/gcd(m,n);
if(ans&1) puts("NO");
else cout<<(m+n)/gcd(m,n)-1<