思路:紫书上的思路 主要是优先队列BFS 结构体的运算符重载需要注意,还有具体不足D的写法也要注意
#include<bits/stdc++.h>
using namespace std;
int cap[3];
int dis[210][210], mark[210][210],vis[210][210];
int ans[210];
struct Node{
int v[3],dis;
bool operator<(const Node&b)const {//两个const 及大于小于号需要注意
return dis>b.dis;
}
};
void update_ans(Node&u){
for(int i=0;i<3;i++){
if(ans[u.v[i]]<0||u.dis<ans[u.v[i]])ans[u.v[i]]=u.dis;
}
}
void solve(int a,int b,int c,int d){
cap[0]=a; cap[1]=b;cap[2]=c;
memset(mark,0,sizeof(mark)); //记录是否访问过
memset(ans,-1,sizeof(ans)); //记录and[d],d容量时倒水量最少的值
memset(dis,-1,sizeof(dis)); //记录dis[a][b],第一个,第二个水量分别为a,b时最小的到水量,用于后面剪枝
Node start;
start.v[0]=0;start.v[1]=0;start.v[2]=c;
start.dis=0;
priority_queue<Node>q;
q.push(start);
dis[0][0]=0;
while(!q.empty()){
Node u=q.top();
q.pop();
if(mark[u.v[0]][u.v[1]])continue;
mark[u.v[0]][u.v[1]]=1;
update_ans(u);
for(int i=0;i<3;i++)
for(int j=0;j<3;j++){
if(i!=j){
if(u.v[i]==0||u.v[j]==cap[j])continue;
int amount=min(cap[j],u.v[i]+u.v[j])-u.v[j];
Node temp=u;
temp.v[i]-=amount;
temp.v[j]+=amount;
temp.dis+=amount;
int&D=dis[temp.v[0]][temp.v[1]];
if(D<0||temp.dis<D){
D=temp.dis;
q.push(temp);
}
}
}
}
while(d>=0){
if(ans[d]>=0){
printf("%d %d\n",ans[d],d); //找出用水量最少的最接近D的值
break;
}
d--;
}
}
int main(){
int t;
scanf("%d",&t);
while(t--){
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
solve(a,b,c,d);
}
return 0;
}