[UVA 10603]Fill

这就是一道小学奥数倒水题(滑稽)

言归正传,首先注意到数据范围很小,只有200,那么可以把三个杯子里的水量作为一个状态进行暴力bfs,显然水的总量一定,只要知道前两个杯子有多少水这个状态就确定了,也就是说状态最多200x200种,很小的。

再考虑下贪心,到某个杯子水量为d的最小倒水量一定由前一个状态倒水量最小值搜索过来的,所以用一个优先队列存状态,按倒水量建个小根堆。

最后如果实现不了某个杯子水量为d,还需要找到一个最接近的。于是我们可以用一个ans数组存储当一个杯子水量为i时的最小值,那么到不了d的话只需要不断向下找ans数组总会有这样一个d被更新。

参考代码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define inf 1e9
using namespace std;
struct pos
{
    int v[4];
    int sum;
    bool operator < (const pos &a) const
    {
        return sum > a.sum;
    }
};
int v[5],d,ans[210];
bool vis[210][210][210];
void bfs() 
{
    memset(vis,0,sizeof(vis));
    memset(ans,-1,sizeof(ans));
    priority_queue<pos>q;
    pos top,node;
    top.v[1] = top.v[2] = 0;
    top.v[3] = v[3];
    top.sum = 0;
    vis[0][0][v[3]] = 1;
    q.push(top);
    while(q.size())
    {
        top = q.top();
        q.pop();
        for(int i = 1;i <= 3;i++)
        {
            if(ans[top.v[i]] < 0 || ans[top.v[i]] > top.sum) ans[top.v[i]] = top.sum;
        }
        if(ans[d] > 0) return;
        for(int i = 1;i <= 3;i++)
        {
            for(int j = 1;j <= 3;j++)
            {    
                if(i == j) continue;     
                if(!top.v[j]) continue;    
                pos tmp;
                if(top.v[j] + top.v[i] > v[i])
                {
                    tmp.v[i] = v[i];
                    tmp.v[j] = top.v[j] + top.v[i] - v[i];
                    tmp.v[6 - i - j] = top.v[6 - i - j];
                    tmp.sum = top.sum + v[i] - top.v[i];
                }
                else
                {
                    tmp.v[i] = top.v[i] + top.v[j];
                    tmp.v[j] = 0;
                    tmp.v[6 - i - j] = top.v[6 - i - j];  
                    tmp.sum = top.sum + top.v[j];
                }
                if(!vis[tmp.v[1]][tmp.v[2]][tmp.v[3]])
                {
                    vis[tmp.v[1]][tmp.v[2]][tmp.v[3]] = 1;
                    q.push(tmp);
                }
            }
        }
    }
    return;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d %d %d",&v[1],&v[2],&v[3],&d);
        bfs();
        while(ans[d] == -1) d--;
        printf("%d %d\n",ans[d],d);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lijilai-oi/p/10737750.html