您的位置:首页 > 其它

USACO section 1.4.4 Mother's Milk

2012-04-15 14:42 330 查看
1. 用dfs,[A][B][C]为三个状态,且只有6个操作,a倒b,a倒c,b倒a,b倒c,c倒a,c倒b。知道用深搜了,但是还是不知道怎么写,看了别人的代码,才会写dfs()这个函数了。其实确定深搜了之后,写这个函数的时候,不需要考虑递归是怎么进行的,只需要考虑这次和下一次的操作过程即可。

2. 以下是代码:

/*
ID: dollar4
PROG: milk3
LANG: C++
*/
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <cstring>

using namespace std;
int a, b, c, p = 0, isin[20];
int vis[21][21][21];
int ans[21];
bool cmp(int a, int b)
{
return a < b;
}
void dfs(int aa, int bb, int cc)
{
if (vis[aa][bb][cc])
return;
vis[aa][bb][cc] = 1;
if (aa == 0 && !isin[cc])
{

isin[cc] = 1;
ans[p++] = cc;
}
if (aa >= b - bb)//a->b
dfs(aa - b + bb, b, cc);
else dfs(0, bb + aa, cc);
if (bb >= a - aa)// b->a
dfs(a, bb - a + aa, cc);
else dfs(aa + bb, 0, cc);
if (cc >= b - bb) // c->b
dfs(aa, b, cc - b + bb);
else dfs(aa, bb + cc, 0);
if (cc >= a - aa) // c->a
dfs(a, bb, cc - a + aa);
else dfs(aa + cc, bb, 0);
if (aa >= c - cc) // a->c
dfs(aa - c + cc, bb, c);
else dfs(0, bb, cc + aa);
if (bb >= c - cc) // b->c
dfs(aa, bb - c + cc, c);
else dfs(aa, 0, cc + bb);
return;
}
int main()
{
ofstream fout ("milk3.out");
ifstream fin ("milk3.in");
memset(vis, 0, sizeof(vis));
memset(isin, 0, sizeof(isin));
memset(ans, 0, sizeof(ans));
fin >> a >> b >> c;
dfs(0, 0, c);
sort(ans, ans + p, cmp);
int cnt = p - 1;
for (int i = 0; i < p; i++)
{
fout << ans[i];
if (cnt--)
fout << ' ';
else fout << endl;
}
return 0;
}


3. 官方参考代码

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: