非常可乐 HDU - 1495 倒水问题 BFS && 数论解法

题目链接:
非常可乐

大意:
有 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
非常可乐 HDU - 1495 倒水问题 BFS && 数论解法_第1张图片
注意题目条件:
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<

你可能感兴趣的:(※,acm,和算法,BFS,线性方程,搜索)