UVA_10603

这个题目和普通的倒水问题不同的是,它不是去求最少的倒水次数,而是求最少的倒水量。普通倒水问题的解法可以参考刘汝佳白书P131

因而我们的判重的时候不能笼统地把所有重复的状态都抛弃,因为有些状态尽管是相同的,但倒水量却有可能不同。

于是我们在判重之前,也应分析一下这个状态会不会对我们记录的达到某一水量时所需的倒水总量进行更新,如果进行了更新,那么即使状态与之前相同,我们也应把这个状态当作一个新的状态来处理。

那么既然如果更新了记录即便是重复的状态也要当作新状态来处理,我们还有必要进行判重吗?实际上也存在着没有更新记录但确实是一个新状态的情况。

    此外,在判重的时候运用了哈希的思想,由于这个题目节点数比较少,所以写一个完美哈希还是比较容易的。

#include<stdio.h>
#include
<string.h>
int hash[8200000],water[210];
int q[3][8200000],st[8200000],a[5];
int insert(newa,newb,newc)
{
int h=0;
h
=201*201*newa+201*newb+newc;
if(!hash[h])
{
hash[h]
=1;
return 1;
}
else
return 0;
}
int main()
{
int i,j,k,t,front,rear,pour,ok;
int A[5],D,newa[5];
scanf(
"%d",&t);
while(t--)
{
scanf(
"%d%d%d%d",&A[0],&A[1],&A[2],&D);
memset(hash,
0,sizeof(hash));
memset(water,
-1,sizeof(water));
a[
0]=0;
a[
1]=0;
a[
2]=A[2];

front
=rear=0;
st[rear]
=0;
for(i=0;i<3;i++)
{
q[i][rear]
=a[i];
water[a[i]]
=st[rear];
}
rear
++;
while(front<rear)
{
for(i=0;i<3;i++)
a[i]
=q[i][front];
front
++;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
if(i!=j)
if(a[i]!=0&&a[j]!=A[j])
{
if(a[i]>A[j]-a[j])
{
pour
=A[j]-a[j];
newa[i]
=a[i]-pour;
newa[j]
=A[j];
}
else
{
pour
=a[i];
newa[i]
=0;
newa[j]
=a[j]+pour;
}
for(k=0;k==i||k==j;k++);
newa[k]
=a[k];
st[rear]
=st[front-1]+pour;
ok
=0;
for(k=0;k<3;k++)
{
q[k][rear]
=newa[k];
if(water[newa[k]]<0||st[rear]<water[newa[k]])
{
ok
=1;
water[newa[k]]
=st[rear];
}
}
if(insert(newa[0],newa[1],newa[2])||ok)
rear
++;
}
}
if(water[D]!=-1)
printf(
"%d %d\n",water[D],D);
else
{
for(i=D;;i--)
if(water[i]!=-1)
break;
printf(
"%d %d\n",water[i],i);
}
}
return 0;
}

  

posted on 2011-09-11 09:34  Staginner  阅读(758)  评论(0编辑  收藏  举报