USACO Mother's Milk

1、倒水问题的变形,把上一个程序(UVa 10603 Fill)改改就行了,一次AC~

/*
ID:mrxy564
PROG:milk3
LANG:C++
*/
#include<cstdio>
#include<cstring>
using namespace std;
struct node{
    int v[3];
};
int vis[21][21];
int cap[3],in[21];
int front,rear,num=0;
bool flag;
node q[450];
node pour(int i,int j,const node &now){
     node next=now;
     if(next.v[i]<=cap[j]-now.v[j]){
          next.v[j]+=now.v[i];
          next.v[i]=0;
     }else{
          next.v[i]-=cap[j]-now.v[j];
          next.v[j]=cap[j];
     }
     return next;
}
void bfs(){
    q[0].v[0]=0;q[0].v[1]=0;q[0].v[2]=cap[2];
    vis[0][0]=1;in[cap[2]]=1;num++;
    front=0;rear=1;
    while(front<rear){
        node &n=q[front];
        for(int i=0;i<3;i++)
           for(int j=0;j<3;j++)
               if(i!=j){
                  node& t=q[rear];
                  node temp=pour(i,j,q[front]);
                  if(!vis[temp.v[0]][temp.v[1]]){
                      t=temp;
                      rear++;
                      if(!in[temp.v[2]]&&temp.v[0]==0){in[temp.v[2]]=1;num++;}
                      vis[temp.v[0]][temp.v[1]]=1;
                  }
               }
        front++;
    }
    return;
}
int main(){
    freopen("milk3.in","r",stdin);
    freopen("milk3.out","w",stdout);
    memset(vis,0,sizeof(vis));
    memset(in,0,sizeof(in));
    for(int i=0;i<3;i++)
        scanf("%d",&cap[i]);
    bfs();
    int i=0;
    while(num--){
        while(!in[i]) i++;
        printf("%d",i);
        i++;
        if(num>0) printf(" ");
        else printf("\n");
    }
    return 0;
}
官方题解:

We use a simple depth-first search to find all the possible states for the three buckets, pruning the search by not researching from states we've seen before.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>

#define MAX 20

typedef struct State	State;
struct State {
    int a[3];
};

int seen[MAX+1][MAX+1][MAX+1];
int canget[MAX+1];

State
state(int a, int b, int c)
{
    State s;

    s.a[0] = a;
    s.a[1] = b;
    s.a[2] = c;
    return s;
}

int cap[3];

/* pour from bucket "from" to bucket "to" */
State
pour(State s, int from, int to)
{
    int amt;

    amt = s.a[from];
    if(s.a[to]+amt > cap[to])
	amt = cap[to] - s.a[to];

    s.a[from] -= amt;
    s.a[to] += amt;
    return s;
}

void
search(State s)
{
    int i, j;

    if(seen[s.a[0]][s.a[1]][s.a[2]])
	return;

    seen[s.a[0]][s.a[1]][s.a[2]] = 1;

    if(s.a[0] == 0)	/* bucket A empty */
	canget[s.a[2]] = 1;

    for(i=0; i<3; i++)
    for(j=0; j<3; j++)
	search(pour(s, i, j));	
}

void
main(void)
{
    int i;
    FILE *fin, *fout;
    char *sep;

    fin = fopen("milk3.in", "r");
    fout = fopen("milk3.out", "w");
    assert(fin != NULL && fout != NULL);

    fscanf(fin, "%d %d %d", &cap[0], &cap[1], &cap[2]);

    search(state(0, 0, cap[2]));

    sep = "";
    for(i=0; i<=cap[2]; i++) {
	if(canget[i]) {
	    fprintf(fout, "%s%d", sep, i);
	    sep = " ";
	}
    }
    fprintf(fout, "\n");

    exit(0);
}

Ran Pang from Canada sends this non-recursive DP solution:

#include<stdio.h>

int m[21][21][21];
int poss[21];
int A, B, C;

int main(void) {
    int i,j,k;
    int flag;
    FILE* in=fopen("milk3.in","r");
    fscanf(in, "%d %d %d",&A, &B, &C);
    fclose(in);
    for(i=0;i<21;i++)
        for(j=0;j<21;j++)
            for(k=0;k<21;k++)
                m[i][j][k]=0;
    for(i=0;i<21;i++)
        poss[i]=0;
    m[0][0][C]=1;

    for(flag=1;flag;) {
        flag=0;
        for(i=0;i<=A;i++)
            for(j=0;j<=B;j++)
                for(k=0;k<=C;k++) {
                    if(m[i][j][k]) {
                	if(i==0) poss[k]=1;
		        if(i) {
	                    if(j<B) {
                                if(B-j>=i) {
                            	    if( m[0][j+i][k]==0) {
                                        m[0][j+i][k]=1;
                                	flag=1;
                            	    }
                                } else {
                            	    if( m[i-(B-j)][B][k] == 0) {
                                        m[i-(B-j)][B][k] =1;
                                        flag=1;
                                    }
                                }
                            }
                            if(k<C) {
                                if(C-k>=i) {
                                    if( m[0][j][k+i]==0) {
                                        m[0][j][k+i]=1;
                                        flag=1;
                                    }
                                }
                                else {
                                    if( m[i-(C-k)][j][C] == 0) {
                                        m[i-(C-k)][j][C] =1;
                                        flag=1;
                                    }
                                }
                            }
                        }
                        if(j) {
                            if(i<A) {
                                if(A-i>=j) {
                                    if( m[i+j][0][k]==0) {
                                        m[i+j][0][k]=1;
                                        flag=1;
                                    }
                                } else {
                                    if( m[A][j-(A-i)][k] == 0) {
                                        m[A][j-(A-i)][k] =1;
                                        flag=1;
                                    }
                                }
                            }
                            if(k<C) {
                                if(C-k>=j) {
                                    if( m[i][0][k+j]==0) {
                                        m[i][0][k+j]=1;
                                        flag=1;
                                    }
                                } else {
                                    if( m[i][j-(C-k)][C] == 0) {
                                        m[i][j-(C-k)][C] =1;
                                        flag=1;
                                    }
                                }
                            }
                        }
                        if(k) {
                            if(i<A) {
                                if(A-i>=k) {
                                    if( m[i+k][j][0]==0) {
                                        m[i+k][j][0]=1;
                                        flag=1;
                                    }
                                } else {
                                    if( m[A][j][k-(A-i)] == 0) {
                                        m[A][j][k-(A-i)] =1;
                                        flag=1;
                                    }
                                }
                            }
                            if(j<B) {
                                if(B-j>=k) {
                                    if( m[i][j+k][0]==0) {
                                        m[i][j+k][0]=1;
                                        flag=1;
                                    }
                                } else {
                                    if( m[i][B][k-(B-j)] == 0) {
                                        m[i][B][k-(B-j)] =1;
                                        flag=1;
                                    }
                                }
                            }
                        }
            }                   
        }
    }
    {
        FILE* out=fopen("milk3.out", "w");
        for(i=0;i<21;i++) {
            if(poss[i]) {
                fprintf(out,"%d",i);
                i++;
                break;
            }
        }
        for(;i<21;i++) {
            if(poss[i]) {
                fprintf(out, " %d", i);
            }
        }
        fprintf(out,"\n");
    }
    return 0;
}

Daniel Jasper from Germany writes:

Both other solutions (recursive and non-recursive) use a 3D-array to store the states, so that the memory usage is O(N3). However a 2D Array and O(N2) would be enough since a state is uniquely defined by the amount of milk in bucket B and C. The amount of milk in bucket A is size-of-C minus amount-in-C minus amount-in-B. This solution works with it, and is a little bit shorter (though not more elegant):

#include <stdio.h>
int A, B, C;
int CB[21][21]; // All states

void readFile() {
    FILE *f;
    f = fopen("milk3.in", "r");
    fscanf(f, "%d%d%d", &A, &B, &C);
    fclose(f);
}

void writeFile() {
    FILE *f; int i;
    f = fopen("milk3.out", "w");
    for(i = 0; i <= C; i++) {
        if(CB[i][C - i] == 1) {
            if((i != C-B) && (i != 0)) fprintf(f, " ");
            fprintf(f, "%d", i);
        }
    }
    fprintf(f, "\n");
    fclose(f);
}

// do brute-force search, c/b: current state
void search(int c, int b) {
    int a;
    if(CB[c][b] == 1) return; // already searched
    CB[c][b] = 1;
    a = C-b-c; // calc amount in A
    // do all moves:
    // c->b
    if(B < c+b) search(c - (B - b), B);
    else search(0, c + b);
    // b->c
    if(C < c+b) search(C, b - (C - c));
    else search(c + b, 0);
    // c->a
    if(A < c+a) search(c - (A - a), b);
    else search(0, b);
    // a->c
    if(C < c+a) search(C, b);
    else search(c + a, b);
    // b->a
    if(A < b+a) search(c, b - (A - a));
    else search(c, 0);
    // a->b
    if(B < b+a) search(c, B);
    else search(c, b + a);
   }
   
int main () {
    readFile();
    search(C, 0);
    writeFile();
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值