题目链接:
题目描述:
有三个容量分别为a,b,c升的容器(a,b,c都是正整数,且都不超过200),刚开始的时候第一个和第二个杯子都是空的,只有第三个杯子装满了c升水。允许从一个容器把水倒入另一个容器中,直到一个容器空了或者是另一个容器满了,允许无限次的进行这样的倒水操作。
你的任务是编写一个程序来计算出最少需要倒多少升水才能让其中某一个杯子中的水有d升(d是不超过200的正整数)?如果无法做到恰好是d升,就让某一个杯子里的水是d‘升,其中d’<d并且尽量接近d。如果能够找到这样的d’,你还是需要计算出其中某一个杯子达到d’升时,最少需要倒多少升水。
题解:
将三个杯子分别装有x,y,z的水时记为状态f(x,y,z),对应与一个点,最多200^3个点,进行一次倒水之后会到达一个新的状态f(x’,y’,z’),从f(x,y,z)到f(x’,y’,z’)建一条有向边,边权为倒的水的数量,从每个状态出发最多有6条边。形成一个带权有向图。跑最短路即可。
因为水的总量不会改变,即x+y+z==c,所以可以只记录x,y,z=c-x-y,状态总数就只有200^2个,可以比上面快100倍。(三元状态建图也能过)
代码:
#include <bits/stdc++.h>
#define LL long long
#define LD long double
#define ULL unsigned long long
#define UI unsigned int
#define PII pair<int,int>
#define MPII(x,y) pair<int,int>{x,y}
#define _for(i,j,k) for(int i=j;i<=k;i++)
#define for_(i,j,k) for(int i=j;i>=k;i--)
#define efor(i,u) for(int i=head[u];i;i=net[i])
#define lowbit(x) (x&-x)
#define ls(x) x<<1
#define rs(x) x<<1|1
#define inf 0x3fffffff
//#pragma comment(linker, "/STACK:10240000000,10240000000")
using namespace std;
const int maxn = 8e6 + 5;
const int M = 1e9 + 7;
inline int mad(int a,int b){return (a+=b)>=M?a-M:a;}
struct E{
int v,w;
}e[maxn<<1];
int id[201][201],vcnt;
int head[maxn],net[maxn<<1],cnt;
void add(int u,int v,int w){
e[++cnt]=E{v,w};
net[cnt]=head[u];
head[u]=cnt;
}
int T,a,b,c,d;
void dfs(int x,int y){
if(id[x][y]) return;
int u= id[x][y]=++vcnt;
int dt,z=c-x-y;
if(x&&y<b){//x->y
dt=min(x,b-y);
if(!id[x-dt][y+dt]) dfs(x-dt,y+dt);
add(u,id[x-dt][y+dt],dt);
}
if(x&&z<c){//x->z
dt=min(x,c-z);
if(!id[x-dt][y]) dfs(x-dt,y);
add(u,id[x-dt][y],dt);
}
if(y&&x<a){//y->x
dt=min(y,a-x);
if(!id[x+dt][y-dt]) dfs(x+dt,y-dt);
add(u,id[x+dt][y-dt],dt);
}
if(y&&z<c){//y->z
dt=min(y,c-z);
if(!id[x][y-dt]) dfs(x,y-dt);
add(u,id[x][y-dt],dt);
}
if(z&&x<a){//z->x
dt=min(z,a-x);
if(!id[x+dt][y]) dfs(x+dt,y);
add(u,id[x+dt][y],dt);
}
if(z&&y<b){//z->y
dt=min(z,b-y);
if(!id[x][y+dt]) dfs(x,y+dt);
add(u,id[x][y+dt],dt);
}
}
int dis[maxn];
priority_queue<PII,vector<PII>,greater<PII> > q;
void dj(int u){
_for(i,1,vcnt) dis[i]=inf;
dis[u]=0;
q.push(PII{0,u});
int w;
while(!q.empty()){
u=q.top().second;
w=q.top().first;
q.pop();
if(w>dis[u]) continue;
for(int i=head[u];i;i=net[i]){
if(dis[e[i].v]>dis[u]+e[i].w){
dis[e[i].v]=dis[u]+e[i].w;
q.push(PII{dis[e[i].v],e[i].v});
}
}
}
}
int an[202];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>a>>b>>c>>d;
dfs(0,0);
dj(1);
_for(i,0,200) an[i]=inf;
_for(x,0,a) _for(y,0,b) {
int z=c-x-y;
int u=id[x][y];
if(u){
an[x]=min(an[x],dis[u]);
an[y]=min(an[y],dis[u]);
an[z]=min(an[z],dis[u]);
}
}
for_(i,d,0){
if(an[i]!=inf){
cout<<an[i]<<" "<<i<<"\n";
break;
}
}
_for(i,1,vcnt) head[i]=0;
_for(x,0,a) _for(y,0,b) id[x][y]=0;
vcnt=cnt=0;
}
return 0;
}