1. 程式人生 > >J - Fill (UVA - 10603)

J - Fill (UVA - 10603)

amp pop 標記 思路 operator OS string sta post

- 題目大意

有三個已知體積但不知刻度的杯子,前兩個杯子中初始時沒有水,第三個裝滿水,問是否可以倒出d升水,如果倒不出,則倒出一個最大的d’,使得d’<=d,並且在這個過程中要求總倒水量最少。

- 解題思路

可以用DFS加上優先隊列來解決,以前兩個杯子中的水量作為標記狀態。只不過這次不是要求的最求最少步數,而是要求最少倒水量即可。

- 代碼

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstring>
#include<stack>
#include<queue>
using namespace std;
int maps[500][500];
int cnt[500];
struct Edge
{
    int m[3],sum;
    Edge(int a,int b,int c,int s)
    {
        m[0]=a,m[1]=b,m[2]=c,sum=s;
    }
    bool operator <(const Edge &rhs)const{
       return sum>rhs.sum;
     }
};

void bfs(int a,int b,int c,int d)
{
    int num[3]={a,b,c};
    priority_queue<Edge>q;
    memset(maps,0,sizeof(maps));
    memset(cnt,-1,sizeof(cnt));
    maps[0][0]=1;
    q.push(Edge(0,0,c,0));
    while(!q.empty())
    {
        Edge u=q.top();
        q.pop();
        for(int i=0;i<3;i++)
        {
            if(cnt[u.m[i]]<0||u.sum<cnt[u.m[i]])
                cnt[u.m[i]]=u.sum;
        }
        if(cnt[d]>=0)
            break;
        for(int i=0;i<3;i++)
        {
            if(u.m[i]==num[i])
                continue;
            for(int j=0;j<3;j++)
            {
                if(i==j||u.m[j]==0)
                    continue;
                int mid=min(num[i],u.m[j]+u.m[i])-u.m[i];
                Edge tmp=u;
                tmp.sum+=mid;
                tmp.m[i]+=mid;
                tmp.m[j]-=mid;
                if(!maps[tmp.m[0]][tmp.m[1]])
                {
                    maps[tmp.m[0]][tmp.m[1]]=1;
                    q.push(tmp);
                }
            }
        }
    }
    while(d>=0)
    {
        if(cnt[d]>=0)
          {
              printf("%d %d\n",cnt[d],d);
              return;
    }
    --d;
    }
}

int main()
{
    int a,b,c,d;
    int n;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%d%d%d%d",&a,&b,&c,&d);
        bfs(a,b,c,d);
    }
    return 0;
}

  

J - Fill (UVA - 10603)