題目鏈接:
題目描述:
有三個容量分別爲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;
}