【M - 非常可乐】

3个瓶子平分水量的BFS思路与代码

思路:

  • 简单的 6入口 BFS,但是:

    1. 我的思路偏了:
      一开始我以为是3个瓶子只要有一个达到 1/2总水量 就可以了(前两张代码),后来发现样例 4 1 3 的答案是 3 不是 2,就以为是只能用杯子喝水,可以喝很多次(第三张代码),但是这样会出现一个比较难解决的问题就是最后一个人喝完,另一个人还需要倒几次水有些难写,终于放弃了。
    2. 第一张代码 map 的操作出了问题,尚未修复
  • 去搜题解,原来题意是:
    使用3个瓶子其中的2个,达到平分的效果。
    那么就仅仅改动一下第二张代码的结束条件就可以了,没有什么特殊的。

代码:

  • 第一版 map:
#include <iostream>
#include <queue>
#include <map>

using namespace std;


struct pot{
	int x,y,z;
	int step ;
	pot(int x,int y,int z,int step) : x(x) , y(y) , z(z) , step(step) {} ;
	friend bool operator < (const pot &a,const pot &b){
		return a.step < b.step;
	}
};
queue<pot> Q;
map<pot , bool> M;//map是<less>类有序容器,使用结构体要重载小于号 
int s,m,n;
int ans;

void init(){
	while(Q.size())
		Q.pop();
	M.clear();
	ans = 0;
	return ;
}

void POUR(int x,int y,int z,int step){
	int nx,ny,nz;
	int ns = step+1;//变量不要重名! 
	for(int i=1;i<=6;i++){
		nx=x,ny=y,nz=z;
		switch(i){
			case 1://s->m
				if(x+y<=m)
					nx=0,ny=x+y;
				else
					nx=x+y-m,ny=m;
				break;
			case 2://s->n
				if(x+z<=n)
					nx=0,nz=x+z;
				else
					nx=x+z-n,nz=n;
				break;
			case 3://m->s
				if(y+x<=s)
					nx=y+x,ny=0;
				else
					nx=s,ny=x+y-s;
				break;
			case 4://m->n
				if(y+z<=n)
					ny=0,nz=y+z;
				else
					ny=y+z-n,nz=n;
				break;
			case 5://n->s
				if(z+x<=s)
					nx=x+z,nz=0;
				else
					nx=s,nz=x+z-s;
				break;
			case 6://n->m
				if(z+y<=m)
					ny=z+y,nz=0;
				else
					ny=m,nz=y+z-m;
				break;
		}
		cout<<M[pot(nx,ny,nz,0)]<<endl;//输出永远是 1 1 1 1 1 1 NO 
		if(M[pot(nx,ny,nz,0)])
			continue;
		M.insert(map<pot,bool>::value_type(pot(nx,ny,nz,0),true));
		Q.push(pot(nx,ny,nz,ns));
	}
	return ;
}

void BFS(){
	Q.push(pot(s,0,0,0));
	M.insert(map<pot,bool>::value_type(pot(s,0,0,0) , true));//map中的step全部置零。
	//那这么一想,vis[maxn][maxn][maxn]足以解决问题,并不需要 map 
	while(Q.size()){
		pot cur = Q.front() ; Q.pop() ;
		int x = cur.x;
		int y = cur.y;
		int z = cur.z;
		if(x + y == z || x + z == y || y + z == x){
			ans = cur.step;
			break;
		}
		POUR(x,y,z,cur.step);
	}
	return ;
}

int main(){
	while(cin>>s>>m>>n && s){
		init();
		BFS();
		if(ans)
			cout<<ans<<endl;
		else
			cout<<"NO"<<endl;
	}
	return 0;
}
  • 第一版改进:
#include <iostream>
#include <queue>
#include <cstring>

using namespace std;

const int maxn = 105;

struct pot{
	int x,y,z;
	int step ;
	pot(int x,int y,int z,int step) : x(x) , y(y) , z(z) , step(step) {} ;
};
queue<pot> Q;
int s,m,n;
int ans;
bool vis[maxn][maxn][maxn];

void init(){
	while(Q.size())
		Q.pop();
	ans = 0;
	memset(vis,false,sizeof(vis));
	return ;
}

void POUR(int x,int y,int z,int step){
	int nx,ny,nz;
	int ns = step+1;//变量不要重名! 
	for(int i=1;i<=6;i++){
		nx=x,ny=y,nz=z;
		switch(i){
			case 1://s->m
				if(x+y<=m)
					nx=0,ny=x+y;
				else
					nx=x+y-m,ny=m;
				break;
			case 2://s->n
				if(x+z<=n)
					nx=0,nz=x+z;
				else
					nx=x+z-n,nz=n;
				break;
			case 3://m->s
				if(y+x<=s)
					nx=y+x,ny=0;
				else
					nx=s,ny=x+y-s;
				break;
			case 4://m->n
				if(y+z<=n)
					ny=0,nz=y+z;
				else
					ny=y+z-n,nz=n;
				break;
			case 5://n->s
				if(z+x<=s)
					nx=x+z,nz=0;
				else
					nx=s,nz=x+z-s;
				break;
			case 6://n->m
				if(z+y<=m)
					ny=z+y,nz=0;
				else
					ny=m,nz=y+z-m;
				break;
		}
		if(vis[nx][ny][nz])
			continue;
		Q.push(pot(nx,ny,nz,ns));
		vis[nx][ny][nz] = true;
	}
	return ;
}

void BFS(){
	Q.push(pot(s,0,0,0));
	vis[s][0][0] = true; 
	while(Q.size()){
		pot cur = Q.front() ; Q.pop() ;
		int x = cur.x;
		int y = cur.y;
		int z = cur.z;
		if(x + y == z || x + z == y || y + z == x){
			ans = cur.step;
			break;
		}
		POUR(x,y,z,cur.step);
	}
	return ;
}

int main(){
	while(cin>>s>>m>>n && s){
		init();
		BFS();
		if(ans)
			cout<<ans<<endl;
		else
			cout<<"NO"<<endl;
	}
	return 0;
}
  • 第二版 POUR_DRINK:
#include <iostream>
#include <queue>
#include <cstring>

using namespace std;

const int maxn = 105;

int S,M,N;
int ans;
int tar;
bool vis[maxn][maxn][maxn];
struct pot{
	int x,y,z;
	int A;//此时先喝水的人已经喝到了多少水 
	int step;
	pot(int a,int b,int c,int d,int e) : x(a) , y(b) , z(c) , A(d) , step(e) {} ;
};
queue<pot> Q;

void init(){
	tar = S/2;
	memset(vis,false,sizeof(vis));
	while(Q.size())
		Q.pop();
	ans = 0;
	return ;
}

void POUR_DRINK(int x,int y,int z,int A,int s){
	int nx,ny,nz,nA,ns;
	for(int i=1;i<=6;i++){
		nx=x,ny=y,nz=z,nA=A,ns=s+1;
		switch(i){
			case 1://S->M
				if(x+y<=M)
					nx=0,ny=x+y;
				else
					nx=x+y-M,ny=M;
				break;
			case 2://S->N
				if(x+z<=N)
					nx=0,nz=x+z;
				else
					nx=x+z-N,nz=N;
				break;
			case 3://M->S
				if(y+x<=S)
					nx=y+x,ny=0;
				else
					nx=S,ny=x+y-S;
				break;
			case 4://M->N
				if(y+z<=N)
					ny=0,nz=y+z;
				else
					ny=y+z-N,nz=N;
				break;
			case 5://N->S
				if(z+x<=S)
					nx=x+z,nz=0;
				else
					nx=S,nz=x+z-S;
				break;
			case 6://N->M
				if(z+y<=M)
					ny=z+y,nz=0;
				else
					ny=M,nz=y+z-M;
				break;
		}
		if(vis[nx][ny][nz])
			continue;
		Q.push(pot(nx,ny,nz,nA,ns));vis[nx][ny][nz] = true;
	}
	for(int i=1;i<=2;i++){
		nx=x,ny=y,nz=z,nA=A,ns=s;
		switch(i){
			case 1:
				nA+=y,ny=0;
				break;
			case 2:
				nA+=z,nz=0;
				break;
		}
		if(vis[nx][ny][nz])
			continue;
		if(nA == tar){
			ans = ns;
			break;
		}
		if(nA > tar)
			continue;
		Q.push(pot(nx,ny,nz,nA,ns));vis[nx][ny][nz]=true;
	}
	return ;
}

void BFS(){
	if(S%2)
		return ;
	Q.push(pot(S,0,0,0,0));vis[S][0][0] = true;
	while(Q.size()){
		pot cur = Q.front();Q.pop();
		int x = cur.x , y = cur.y , z = cur.z , A = cur.A , step = cur.step ;
		POUR_DRINK(x,y,z,A,step);
		if(ans)
			break;
	}
	return ;
}

int main(){
	while(cin>>S>>M>>N && S){
		init();
		BFS();
		if(ans)
			cout<<ans<<endl;
		else
			cout<<"NO"<<endl;
	}
	return 0;
}
  • 265ms 2552kB
//265ms		2552kB


#include <iostream>
#include <queue>
#include <cstring>

using namespace std;

const int maxn = 105;

struct pot{
	int x,y,z;
	int step ;
	pot(int x,int y,int z,int step) : x(x) , y(y) , z(z) , step(step) {} ;
};
queue<pot> Q;
int s,m,n;
int ans;
bool vis[maxn][maxn][maxn];

void init(){
	while(Q.size())
		Q.pop();
	ans = 0;
	memset(vis,false,sizeof(vis));
	return ;
}

void POUR(int x,int y,int z,int step){
	int nx,ny,nz;
	int ns = step+1;//变量不要重名! 
	for(int i=1;i<=6;i++){
		nx=x,ny=y,nz=z;
		switch(i){
			case 1://s->m
				if(x+y<=m)
					nx=0,ny=x+y;
				else
					nx=x+y-m,ny=m;
				break;
			case 2://s->n
				if(x+z<=n)
					nx=0,nz=x+z;
				else
					nx=x+z-n,nz=n;
				break;
			case 3://m->s
				if(y+x<=s)
					nx=y+x,ny=0;
				else
					nx=s,ny=x+y-s;
				break;
			case 4://m->n
				if(y+z<=n)
					ny=0,nz=y+z;
				else
					ny=y+z-n,nz=n;
				break;
			case 5://n->s
				if(z+x<=s)
					nx=x+z,nz=0;
				else
					nx=s,nz=x+z-s;
				break;
			case 6://n->m
				if(z+y<=m)
					ny=z+y,nz=0;
				else
					ny=m,nz=y+z-m;
				break;
		}
		if(vis[nx][ny][nz])
			continue;
		Q.push(pot(nx,ny,nz,ns));
		vis[nx][ny][nz] = true;
	}
	return ;
}

void BFS(){
	Q.push(pot(s,0,0,0));
	vis[s][0][0] = true; 
	while(Q.size()){
		pot cur = Q.front() ; Q.pop() ;
		int x = cur.x;
		int y = cur.y;
		int z = cur.z;
		if((x == y && !z)||(x == z && !y)||(y == z)&&!x){
			ans = cur.step;
			break;
		}
		POUR(x,y,z,cur.step);
	}
	return ;
}

int main(){
	while(cin>>s>>m>>n && s){
		init();
		BFS();
		if(ans)
			cout<<ans<<endl;
		else
			cout<<"NO"<<endl;
	}
	return 0;
}
#include <bits/stdc++.h> using namespace std; struct anss { int a,b; }; bool cmp(int n,int m) { if(n.a!=m.a) { return n.a<m.a; } return n.b>m.b; } int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n,m; cin>>n>>m; anss ans[200005]; for(int i = 1;i<=m;i++) { cin>>ans[i].a>>ans[i].b; } sort(ans[1],ans[m],cmp); return 0; } 题目描述 有一家神秘的可乐商店。这家商店不直接出售可乐,而是提供空可乐瓶与新瓶装可乐的兑换服务。 初始时,高桥君拥有 N N 瓶可乐。之后,他可以多次(包括零次)选择以下任意一种操作: 喝掉一瓶可乐:如果他当前有瓶装可乐,可以喝掉一瓶。这样,他拥有的瓶装可乐数量减少 1,空瓶数量增加 1。(如果他没有瓶装可乐,则不能执行此操作。) 兑换操作:选择一个整数 i i( 1 ≤ i ≤ M 1≤i≤M),用 A i A i ​ 个空瓶兑换 B i B i ​ 瓶新可乐和 1 张纪念贴纸。(如果当前空瓶数量不足 A i A i ​ ,则不能选择该 可选,则不能执行此操作。) 高桥君非常喜欢贴纸。请问,在他采取最优策略的情况下,最多能获得多少张贴纸? 初始时,他没有空瓶,也没有贴纸。 约束条件 1 ≤ N ≤ 10 18 1≤N≤10 18 1 ≤ M ≤ 2 × 10 5 1≤M≤2×10 5 1 ≤ B i < A i ≤ 10 18 1≤B i ​ <A i ​ ≤10 18 所有输入均为整数。 输入格式 输入从标准输入按以下格式给出: text N M A_1 B_1 A_2 B_2 ... A_M B_M 输出格式 输出一个整数,表示高桥君最多能获得的贴纸数量。 样例输入 1 text 5 3 5 1 4 3 3 1 样例输出 1 text 3 样例解释 1 高桥君可以按以下步骤操作: 初始有 5 瓶可乐。 喝掉 1 瓶可乐 5 次,得到 5 个空瓶。 选择 i = 2 i=2,用 4 个空瓶兑换 3 瓶可乐和 1 张贴纸。此时有 3 瓶可乐、1 个空瓶和 1 张贴纸。 喝掉 1 瓶可乐 3 次,得到 4 个空瓶。 再次选择 i = 2 i=2,用 4 个空瓶兑换 3 瓶可乐和 1 张贴纸。此时有 3 瓶可乐和 2 张贴纸。 喝掉 1 瓶可乐 3 次,得到 3 个空瓶。 选择 i = 3 i=3,用 3 个空瓶兑换 1 瓶可乐和 1 张贴纸。此时有 1 瓶可乐和 3 张贴纸。 最终,高桥君最多可以获得 3 张贴纸。 样例输入 2 text 3 3 5 1 5 1 4 2 样例输出 2 text 0 样例解释 2 高桥君只能喝掉初始的 3 瓶可乐,无法进行任何兑换操作。 样例输入 3 text 415 8 327 299 413 396 99 67 108 51 195 98 262 180 250 175 234 187 样例输出 3 text 11 解题思路 这是一个典型的贪心问题。我们需要找到最优的兑换顺序,使得高桥君能够获得最多的贴纸。关键在于每次选择“性价比”最高的兑换方式,即用最少的空瓶获得最多的可乐和贴纸。 具体步骤如下: 排序兑换选项:按照 A i − B i A i ​ −B i ​ 从小到大排序(即每次兑换后净消耗的空瓶数最少),这样可以在有限的空瓶下尽可能多地进行兑换。 模拟兑换过程:初始时,高桥君有 N N 瓶可乐和 0 个空瓶。每次尽可能多地喝掉可乐,积累空瓶,然后用空瓶兑换更多的可乐和贴纸,直到无法继续兑换为止。 计算最大贴纸数:在每次兑换时,计算当前可以进行的最大兑换次数,并累加贴纸数量。 扩写
最新发布
07-20
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值