题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4490
Mad Veterinarian
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 279 Accepted Submission(s): 111
Special Judge
Machine A turns one ant into one beaver.
Machine B turns one beaver into one ant, one beaver and one cougar.
Machine C turns one cougar into one ant and one beaver.
Can we convert a beaver and a cougar into 3 ants?
Can we convert one ant into 2 ants? NO
These puzzles have the properties that:
1. In forward mode, each machine converts one animal of a given species into a finite, non-empty collection of animals from the species in the puzzle.
2. Each machine can operate in reverse.
3. There is one machine for each species in the puzzle and that machine (in forward mode) takes as input one animal of that species.
Write a program to find the shortest solution (if any) to Mad Veterinarian puzzles. For this problem we will restrict to Mad Veterinarian puzzles with exactly three machines, A, B, C.
The first line of each data set consists of two decimal integers separated by a single space. The first integer is the data set number. The second integer is the number, N, of puzzle questions. The next three input lines contain the descriptions of machines A, B and C in that order. Each machine description line consists of three decimal integers separated by spaces giving the number of animals of type a, b and c output for one input animal. The following N lines give the puzzle questions for the Mad Veterinarian puzzle. Each contains seven decimal digits separated by single spaces: the puzzle number, the three starting animal counts for animals a, b and c followed by the three desired ending animal counts for animals a, b and c.
2 1 2 0 1 0 1 1 1 1 1 0 1 0 1 1 3 0 0 2 1 0 0 2 0 0 2 2 0 3 4 0 0 5 0 0 3 1 2 0 0 0 0 5 2 2 0 0 0 0 4
1 2 1 3 Caa 2 NO SOLUTION 2 2 1 NO SOLUTION 2 25 AcBcccBccBcccAccBccBcccBc
不想再看了,写的想吐了。。。。明天再来说我是怎么一路错过来的。。。。。
不是它不水,是我比它更水!!!!!!
题意:三个机器,换小动物。每种机器有一种操作A、B、C。也可以对小动物实现A、B、C的逆操作abc。给定初状态和末状态,问能不能通过6种操作从初状态达到
末状态。
分析:很裸的BFS+记录路径。
感想:
好多写错和想错的位置-------------
1、致命的错误是:没有先判断能不能换,而是直接录入A、B、C三种操作然后对应的-1,这样处理成辅助数组了以后搜。但是这样是不行的,比如:C操作是0 0 2,
如果按我之前的做法,当z为0的时候可以变成1,但是没有小动物,怎么能无中生有呢。自然界都没这种神奇的事发生呢!所以错,要先判断,再相应的减去消耗
的小动物。
2、乱使用宏定义。开始把abcABC定义成宏,而末状态什么的又用ea、eb、ec记录。这样很危险的,因为宏就是直接替代呀,ea eb ec不就成了 e1 e2 e3。难怪调试
时发现末状态突然就变了,但是我又没有语句去改它。
3、链表指针混乱了,导致死循环。我对链表和内存的理解真的是太浅薄了。我开始只开了state cur,next。最后每次只是改了cur对应内存的数值,每次都把指针指向cur
这一个内存空间,最后输出的时候就总输出a停不下来。现在想想,那还叫链表么。后来改成了开个大数组 state snode[100000],在队列里放state的指针。用遍历
指针每次从队列里取一个指针出来。然后得到新状态在把状态存到snode数组里,相应的地址存进队列。
4、我开始犯了个很BT的错误,为什么以为只要大于-1就可以了,小于-1就continue。改的太久了,忘了最初怎么想的。总之后来next.a什么我以为可以是-1,最后因为
next.a什么的是vis[][][]判重数组的下标,导致数组越界了。
5、其实可以用set判重,当下标可能为负的时候,还有当数据很大很大的时候,vis根本控制不了。比如这题:要不是因为10意外的数据都可以不要了,用if。。continue
掉,vis数组是根本控制不了的。(set判重比vis判重慢 )
6、这题据说hdu oj 的数组很小,直接打表就能过的。其实这题还可以用位运算写,因为状态最多只有12 (只针对这题),用个整形的int ,前24位记录aa bb cc三个数,另外
8位记录选择的路径。加减的话就是在整形的移位。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
struct f
{
int x;
int y;
int z;
}ff[3];
struct state
{
int aa;
int bb;
int cc;
char step;
state *pre;
}s;
int ea,eb,ec;
char solve[1100];
bool vis[12][12][12];
int rear;
struct state snode[100000];
bool bfs()
{
int r=0;
queue<state*> q;
while(!q.empty())
q.pop();
s.pre=NULL;
q.push(&s);
vis[s.aa][s.bb][s.cc]=true;
while(!q.empty())
{
struct state *pNow =q.front();
q.pop();
if(pNow->aa==ea && pNow->bb==eb && pNow->cc==ec)
{
rear = 0;
//state *head;
for(;pNow!=NULL;pNow=pNow->pre)
{
solve[rear++]=pNow->step;
}
solve[rear] = '\0';
return true;
}
for(int i=0;i<3;i++)
{
if (i == 0 && pNow->aa < 1 || i == 1 && pNow->bb < 1 || i == 2 && pNow->cc < 1)
continue; //条件不满足
snode[r].aa=pNow->aa+ff[i].x;
snode[r].bb=pNow->bb+ff[i].y;
snode[r].cc=pNow->cc+ff[i].z;
//消耗掉的动物
if (i == 0) --snode[r].aa;
else if (i == 1) --snode[r].bb;
else --snode[r].cc;
if(snode[r].aa>10 || snode[r].bb>10 || snode[r].cc>10) continue;
if(vis[snode[r].aa][snode[r].bb][snode[r].cc]==false)
{
snode[r].step='A' + i;
snode[r].pre=pNow;
q.push(&snode[r]);
vis[snode[r].aa][snode[r].bb][snode[r].cc]=true;
++r;
}
}
//逆序
for (int i = 0; i < 3; ++i)
{
if (pNow->bb < ff[i].y || pNow->cc < ff[i].z || pNow->aa < ff[i].x)
continue; //条件不满足
snode[r].aa=pNow->aa-ff[i].x;
snode[r].bb=pNow->bb-ff[i].y;
snode[r].cc=pNow->cc-ff[i].z;
//增加的动物
if (i == 0) ++snode[r].aa;
else if (i == 1) ++snode[r].bb;
else ++snode[r].cc;
if(snode[r].aa>10 || snode[r].bb>10 || snode[r].cc>10) continue;
if(vis[snode[r].aa][snode[r].bb][snode[r].cc]==false)
{
snode[r].step='a' + i;
snode[r].pre=pNow;
q.push(&snode[r]);
vis[snode[r].aa][snode[r].bb][snode[r].cc]=true;
++r;
}
}
}
return false;
}
int main()
{
int t,i,t1,t2,t3,cs,cas,fuc,j,d;
scanf("%d",&t);
while(t--)
{
memset(ff,0,sizeof(ff));
scanf("%d%d",&cas,&fuc);
for(i=0;i<3;i++)
{
scanf("%d%d%d",&t1,&t2,&t3);
ff[i].x=t1;
ff[i].y=t2;
ff[i].z=t3;
}
printf("%d %d\n",cas,fuc);
for(d=0;d<fuc;d++)
{
rear=0;
memset(vis,0,sizeof(vis));
scanf("%d%d%d%d%d%d%d",&cs,&s.aa,&s.bb,&s.cc,&ea,&eb,&ec);
if(bfs())
{
printf("%d %d",cs,strlen(solve));
if (strlen(solve) > 0) printf(" ");
for (int len = strlen(solve) - 1; len >= 0; --len)
printf("%c", solve[len]);
printf("\n");
}
else printf("%d NO SOLUTION\n",cs);
}
}
return 0;
}