J

- 题目大意

    有三个已知体积但不知刻度的杯子,前两个杯子中初始时没有水,第三个装满水,问是否可以倒出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
",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;
}

  

原文地址:https://www.cnblogs.com/alpacadh/p/8523858.html