1169: PIPI倒水

为什么ans[d]!=-1的时候,就可以return了?
因为使用小根堆,队列后面的节点的倒水量都比现在大,即使后面的节点也可以通过倒水出现d也没用了。

????????
哈哈哈哈哈处是两种代码不一样的地方。
我认为应该等到访问节点的时候,在设置vis为1,而不是在插入的时候,就设置为1。
因为访问节点A的时候插入节点C1,访问节点B的时候像插入节点C2.即使B在A之后,(C1和C2的三杯水相同)不代表A找到的C1一定比C2小吧?但是代码一会不让C2插入优先队列
但是代码2,就可以让C1和C2都插入,且C2会比C1先成为小根堆的堆顶,然后C2先更新ans。

#include <bits/stdc++.h>
using namespace std;
const int N=210;
int cap[3],d; //三个杯子的容量,目标值 
struct node{
	int water[3];
	int dao;//达到当前节点,已经倒的水量
	bool operator<(const node& a) const{
		return dao>a.dao;
	} 
};
int vis[N][N]; //坐标x,y代表第一杯水和第二杯水的水量 
int ans[N];    
void bsf(priority_queue<node> q){
	memset(ans,-1,sizeof(ans));
	memset(vis,0,sizeof(vis));
	ans[cap[2]]=0;ans[0]=0;
	vis[0][0]=1;
	while(!q.empty()){
		auto now=q.top();
		q.pop();
		for(int i=0;i<3;i++){
			if(ans[now.water[i]]==-1||ans[now.water[i]]>now.dao)
				ans[now.water[i]]=now.dao;
		}
		if(ans[d]!=-1){
			return;
		}
		for(int i=0;i<3;i++){
			for(int j=0;j<3;j++){
			
				if(i==j)	
					continue;
				if(now.water[i]==0||now.water[j]==cap[j])
					continue;
				int pour=min(now.water[i],cap[j]-now.water[j]);
				node next=now;
				next.water[i]-=pour;
				next.water[j]+=pour;
				next.dao+=pour;
				if(!vis[next.water[0]][next.water[1]])
					{
					vis[next.water[0]][next.water[1]]=1; //哈哈哈哈哈哈哈哈哈
					q.push(next); 
				}
			}
		}
	}
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d%d",&cap[0],&cap[1],&cap[2],&d);
		node p; p.dao=0; p.water[2]=cap[2];p.water[0]=0;p.water[1]=0;
		priority_queue<node> q; //关于倒水量的小根堆 
		q.push(p);
		bsf(q);
		for(int i=d;i>0;i--){
			if(ans[i]!=-1){
				printf("%d %d\n",ans[i],i);
				break;
			}
			if(i==1){
				printf("%d %d\n",0,0);
			}
		}
	}
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
const int N=210;
int cap[3],d; //三个杯子的容量,目标值 
struct node{
	int water[3];
	int dao;//达到当前节点,已经倒的水量
	bool operator<(const node& a) const{
		return dao>a.dao;
	} 
};
int vis[N][N]; //坐标x,y代表第一杯水和第二杯水的水量 
int ans[N];    
void bsf(priority_queue<node> q){
	memset(ans,-1,sizeof(ans));
	memset(vis,0,sizeof(vis));
	ans[cap[2]]=0;ans[0]=0;      
	while(!q.empty()){
		auto now=q.top();
		q.pop();
		vis[now.water[0]][now.water[1]]=1;        //哈哈哈哈哈哈哈哈哈
		for(int i=0;i<3;i++){
			if(ans[now.water[i]]==-1||ans[now.water[i]]>now.dao)
				ans[now.water[i]]=now.dao;
		}
		if(ans[d]!=-1){
			return;
		}
		for(int i=0;i<3;i++){
			for(int j=0;j<3;j++){
			
				if(i==j)	
					continue;
				if(now.water[i]==0||now.water[j]==cap[j])
					continue;
				int pour=min(now.water[i],cap[j]-now.water[j]);
				node next=now;
				next.water[i]-=pour;
				next.water[j]+=pour;
				next.dao+=pour;
				if(!vis[next.water[0]][next.water[1]])
					{
					q.push(next); 
				}
			}
		}
	}
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d%d",&cap[0],&cap[1],&cap[2],&d);
		node p; p.dao=0; p.water[2]=cap[2];p.water[0]=0;p.water[1]=0;
		priority_queue<node> q; //关于倒水量的小根堆 
		q.push(p);
		bsf(q);
		for(int i=d;i>0;i--){
			if(ans[i]!=-1){
				printf("%d %d\n",ans[i],i);
				break;
			}
			if(i==1){
				printf("%d %d\n",0,0);
			}
		}
	}
	return 0;
}
posted @ 2026-02-11 22:31  peter_shen  阅读(5)  评论(0)    收藏  举报