据说是水题,参考别人代码写了一个晚上。
题意是给两个水杯a<b,给定一个目标水量n,求用 fill A ,fill B ,empty A ,empty B ,pour A B ,pour B A,这几种方式,最少能几次倒出目标水量n。
因为用队列的stl要记录层比较难,所以用数组模拟。
代码:
#include <stdio.h>
#include <string.h>
const int MAX=1005;
int a,b,n,str[MAX*MAX],r,l;
bool vis[MAX][MAX];
char act[][10]= {" ","fill A","fill B","empty A","empty B","pour B A","pour A B"};
struct Point
{
int va;
int vb;
int opr; //记录操作。
int pre; //记录父结点。
} point[MAX*MAX];
void record(int va,int vb,int opr)
{
if(vis[va][vb])
return ;
vis[va][vb]=1;
point[r].va=va;
point[r].vb=vb;
point[r].opr=opr;
point[r].pre=l;
r++;
}
int min(int a,int b)
{
return a>b?b:a;
}
void print()
{
int top,i;
top=0;
while(l!=0)
{
str[top++]=point[l].opr; //因为数组可以记录下所有子结点和父结点,所以用队列写比较吃亏。
l=point[l].pre;
}
for(i=top-1; i>=0; i--)
{
printf("%s\n",act[str[i]]);
}
printf("success\n");
}
void bfs()
{
point[0].va=0;
point[0].vb=0;
vis[0][0]=1;
l=0;
r=1;
while(1)
{
if(point[l].vb==n)
{
print();
return ;
}
int xa,xb,x;
//fill A
xa=a;
xb=point[l].vb;
record(xa,xb,1);
//fill B
xa=point[l].va;
xb=b;
record(xa,xb,2);
//empty A
xa=0;
xb=point[l].vb;
record(xa,xb,3);
//empty B
xa=point[l].va;
xb=0;
record(xa,xb,4);
//pour B A
x=min(a-point[l].va,point[l].vb);
xa=point[l].va+x;
xb=point[l].vb-x;
record(xa,xb,5);
//pour A B
x=min(b-point[l].vb,point[l].va);
xa=point[l].va-x;
xb=point[l].vb+x;
record(xa,xb,6);
l++;
}
}
int main()
{
while(scanf("%d%d%d",&a,&b,&n)!=EOF)
{
memset(vis,0,sizeof(vis));
bfs();
}
return 0;
}
相同类型但是一直RE。。poj3414 T T
真脑残啊,一样的题目错了这么多遍。
但是也许acm迷人的地方也在这里。
题意与上题一样,不一样的地方就是impossible,和a b 大小不确定。
代码:
#include <stdio.h>
#include <string.h>
const int MAX=205;
int a,b,n,str[MAX*MAX],r,l;
bool vis[MAX][MAX];
char act[][10]= {" ","FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(2,1)","POUR(1,2)"};
bool output;
struct Point
{
int va;
int vb;
int opr; //记录操作。
int pre; //记录父结点。
} point[MAX*MAX];
void record(int va,int vb,int opr)
{
if(vis[va][vb])
return ;
vis[va][vb]=1;
point[r].va=va;
point[r].vb=vb;
point[r].opr=opr;
point[r].pre=l;
r++;
}
int min(int a,int b)
{
return a>b?b:a;
}
void print()
{
int top,i;
top=0;
while(l!=0)
{
str[top++]=point[l].opr; //因为数组可以记录下所有子结点和父结点,所以用队列写比较吃亏。
l=point[l].pre;
}
printf("%d\n",top);
for(i=top-1; i>=0; i--)
{
printf("%s\n",act[str[i]]);
}
}
void bfs()
{
point[0].va=0;
point[0].vb=0;
vis[0][0]=1;
l=0;
r=1;
while(l!=r)
{
if(point[l].vb==n||point[l].va==n)//!!不同点
{
output=1;
print();
return ;
}
int xa,xb,x;
//fill A
xa=a;
xb=point[l].vb;
record(xa,xb,1);
//fill B
xa=point[l].va;
xb=b;
record(xa,xb,2);
//empty A
xa=0;
xb=point[l].vb;
record(xa,xb,3);
//empty B
xa=point[l].va;
xb=0;
record(xa,xb,4);
//pour B A
x=min(a-point[l].va,point[l].vb);
xa=point[l].va+x;
xb=point[l].vb-x;
record(xa,xb,5);
//pour A B
x=min(b-point[l].vb,point[l].va);
xa=point[l].va-x;
xb=point[l].vb+x;
record(xa,xb,6);
l++;
}
}
int main()
{
while(scanf("%d%d%d",&a,&b,&n)!=EOF)
{
if((a < n && b < n)||n==0)//!!不同点
{
printf("impossible\n");
continue;
}
output=0;
memset(vis,0,sizeof(vis));
bfs();
if(!output) //!!不同点
printf("impossible\n");
}
return 0;
}
uva 571:
题意同poj的,但思路不一样,这次是数论的思路。
解析:
用到了一个性质:r = k * a mod b,知a,b互素,必定可以得到区间(0, b - 1]的所有数。
所以只要不断模拟这个过程就行了,相当于往a倒水(*k),a中水倒入b内(mod b)。
注意执行顺序。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
using namespace std;
const int maxn = 1e6;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = 4 * atan(1.0);
const double ee = exp(1.0);
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int ca, cb, n;
while (scanf("%d%d%d", &ca, &cb, &n) != EOF)
{
int ta = 0;
int tb = 0;
while (1)
{
if (tb == n)
{
printf("success\n");
break;
}
else if (tb == cb)
{
tb = 0;
printf("empty B\n");
}
else if (ta == 0)
{
ta = ca;
printf("fill A\n");
}
else if (ta != 0)
{
if (tb + ta <= cb)
{
tb += ta;
ta = 0;
}
else
{
ta = ta + tb - cb;
tb = cb;
}
printf("pour A B\n");
}
}
}
return 0;
}