油分離問題に対する C++ ソリューション

原題

(大バレル) 20、(中バレル) 9、(小バレル) 7 の容量を持つ 3 つの石油バレルがあります。大バレルには最初は石油がいっぱいですが、どうすれば 17 個の石油を分離できますか?

コード

#include<iostream>
#include<cmath>
#include<queue>
#include<set>
using namespace std;

class R {
	public:
		int l,v;
};

class T {
	public:
		R a,b,c;
		int last;
		string xw;
		T(R a,R b,R c):a(a),b(b),c(c) {
		}
		T(R a,R b,R c,int last,string xw):a(a),b(b),c(c),last(last),xw(xw) {
		}
		int id() {
			return a.v*100+b.v*10+c.v;
		}
};

void go(R *r1,R *r2) {
	int v=r2->v+r1->v;
	v=min(v,r2->l);
	int cha=v-r2->v;
	r2->v=v;
	r1->v-=cha;
}

void dfs(vector<T> vt,T t) {
	if(t.last==-1){
		cout<<t.xw<<" ==>> "<<t.a.v<<","<<t.b.v<<","<<t.c.v<<endl;
		return;
	}
	dfs(vt,vt[t.last]);
	cout<<t.xw<<" ==>> "<<t.a.v<<","<<t.b.v<<","<<t.c.v<<endl;
}

int main(int argc,char** argv) {

	R a,b,c;
	a.l=20;
	a.v=20;
	b.l=9;
	b.v=0;
	c.l=7;
	c.v=0;

	int targetV=17;

	T t(a,b,c,-1,"init");
	set<int> s;
	queue<T> q;
	q.push(t);
	s.insert(t.id());
	vector<T> vt;

	while(!q.empty()) {
		t=q.front();
		q.pop();
		if(t.a.v==targetV || t.b.v==targetV || t.c.v==targetV) {
			cout<<"Success"<<endl;
			dfs(vt,t);
			break;
		}

		vt.push_back(t);
		int last=vt.size()-1;

		a=t.a;
		b=t.b;
		c=t.c;

		if(a.v>0) {
			if(b.v<b.l) {
				T temp(a,b,c,last,"a->b");
				go(&(temp.a),&(temp.b));
				int id=temp.id();
				if(s.find(id)==s.end()) {
					q.push(temp);
					s.insert(id);
				}
			}
			if(c.v<c.l) {
				T temp(a,b,c,last,"a->c");
				go(&(temp.a),&(temp.c));
				int id=temp.id();
				if(s.find(id)==s.end()) {
					q.push(temp);
					s.insert(id);
				}
			}
		}

		if(b.v>0) {
			if(a.v<a.l) {
				T temp(a,b,c,last,"b->a");
				go(&(temp.b),&(temp.a));
				int id=temp.id();
				if(s.find(id)==s.end()) {
					q.push(temp);
					s.insert(id);
				}
			}
			if(c.v<c.l) {
				T temp(a,b,c,last,"b->c");
				go(&(temp.b),&(temp.c));
				int id=temp.id();
				if(s.find(id)==s.end()) {
					q.push(temp);
					s.insert(id);
				}
			}
		}

		if(c.v>0) {
			if(a.v<a.l) {
				T temp(a,b,c,last,"c->a");
				go(&(temp.c),&(temp.a));
				int id=temp.id();
				if(s.find(id)==s.end()) {
					q.push(temp);
					s.insert(id);
				}
			}
			if(b.v<b.l) {
				T temp(a,b,c,last,"c->b");
				go(&(temp.c),&(temp.b));
				int id=temp.id();
				if(s.find(id)==s.end()) {
					q.push(temp);
					s.insert(id);
				}
			}
		}
	}

	return 0;
}

走る

解析する

1. 各バレルにはその容量と現在の石油量があり、データ構造は次のように定義されます。

class R {
	public:
		int l,v;
};

 容量とオイル量を表示

2. 各操作では、空でないバケットから満杯でない別のバケットにできるだけ多くの油を注ぐことができます(満杯のバケットに注ぐことは意味がないため)。これを理解する必要があります。注油実行機能は

void go(R *r1,R *r2) {
	int v=r2->v+r1->v;
	v=min(v,r2->l);
	int cha=v-r2->v;
	r2->v=v;
	r1->v-=cha;
}

注ぐバケツの容量には限りがあるため、より小さな値で判断する必要があります。

3. 石油注入操作が完了するたびに、現在の 3 つの石油バレルの石油量と、[どのバレルから別のバレルに注ぎ込んだか] という操作を記録するための記録が作成されます。データ構造は次のように定義されます。

class T {
	public:
		R a,b,c;
		int last;
		string xw;
		T(R a,R b,R c):a(a),b(b),c(c) {
		}
		T(R a,R b,R c,int last,string xw):a(a),b(b),c(c),last(last),xw(xw) {
		}
		int id() {
			return a.v*100+b.v*10+c.v;
		}
};

結果を取得した後、これらの操作をすべて出力する必要があるため、ステップを保存するためのリストが必要です。

vector<T> vt;

この場合、属性 T.last はリスト内の前の操作の添字となるため、見つけやすくなります。

T.xwは前回の動作の挙動を表しており、T.xw=="a->b"の場合、バレルaからバレルbに油が注がれることを意味する。

4. キューを開いて、ニーズを満たす操作が見つかるまでオイル注入プロセスをシミュレートし、オイル注入プロセスを印刷して終了します。

5. 解決策がない可能性があるため、状況が繰り返されるのを避けるために各解決策にマークを付ける必要があります。例: 大きなバケツの油を小さなバケツに注いだところです。この時点では、[20,0,0] から始まります。 =>[13,0,7] して、小樽から大樽に油を戻します。この状況を解消する必要があります。関数 T.id は状態を表す識別子です。 3 つのバレル内のオイルの量が表示される この状況が発生した場合は、同様の操作が実行されたことを意味するため、現時点ではこの操作をキューに追加しないでください。

おすすめ

転載: blog.csdn.net/qq_36694133/article/details/134695302