CSP-宿題Week2問題Bは、暗黙的にBFS--問題(C ++)を注ぎます

オリジナルタイトル説明

タイトル説明

「空A」は、水とカップB B Aカップ充填または空に注ぎ、Aで表される空カップ、「ABを注ぐ」と表し、充填カップを表す問題「フィルA」を注ぎます。

入力

入力データの複数のセットを含みます。データ入力A、Bの各セットは、Cデータの範囲は0 <A <= B、C <= B <= 1000、A及びBは互いに素です。

出力

あなたのプログラムの出力は、一連の命令になります。これらの出力ラインはただのユニットのC含む水jarファイルを引き起こす可能性があります。最後に、出力の各データラインは「成功」でなければなりません。出力ラインは、最初の列から始まる任意の空行または末尾のスペースであってはなりません。

サンプル入力

2 7 5
2 7 4

サンプル出力

フィルBは、
BAの注ぐ
成功
フィルAを
ABの注ぐ
フィルAを
AB注ぐ
成功を

タイトルリピート

タイトルの文字通りの意味は、水のC容量のガラスを注ぐ、1は2つのカップを使用して、1つのbは、比較的単純な容量は2つのカップと互いに素であり、問​​題の可解性となっています。

問題解決のためのアイデア

概要アイデア

イタリアは非常に簡単に理解するために見えますが、可能な初めてBFSが、貪欲ではないを使用して考えることではなく、試した後に二つのアプローチ、BFSのソリューションは、比較的容易に実装する小さな境界条件を考えることは困難であると話題問題解決のために使用します。だから、物語BFSソリューション:
隠された核となるアイデアは、検索の種類で見つけると州との境界条件との関係を変換することができるBFSに問題を表示することです。
質問変換の意味:同じ構造体として、あなたが課題を解決するために、より多くの状態の2つのカップよりも疑問に問題を変換することができます2杯を注ぐのプロセスの状態が最終状態を取得するために、初期状態からBFSの検索に変換することができます(A又はB = C)
状態間の変換関係
(ここで、我々はカップの容量、B、Cの代表を使用して、A、Bは一定時間カップの状態を表します)

状態 スイッチング動作を取ります
A> 0 空に
B> 0 空にB
A <A 充填
B <B Bを充填
<&& B> 0 && A + B <A B後方A、及び不満注ぎます
<a && B> 0 && A + B> = A B後方A、Aフィリング
B 0 && A + B <B <A && B> B後方、及び不満注ぎます
B <B && A> 0 && A + B> = B 後方B、及びBのフィリング

BFS境界条件

= C || B = C

データストレージ

この問題の数、注入工程におけるよりも最も重要なデータ、二つの状態間の遷移を注ぎ、BFSプロセスを確実にするために、2つの状態間の各遷移は、このように特定のを見つけることが保証され、一度だけ表示されます少なくとも、我々は2つの状態間で動作を切り替える保存するために、<状況、状態を>マップを使用し、状態にBFSは、我々は唯一のスイッチング動作に対してこの操作を実行する必要があります。

void refresh(status &s, status &t) 
{
    if ( from.find(t) == from.end() ) 
    { // 特判合法,加入队列
        from[t] = s;
        Q.push(t);
    }
}

あなたは、この変換が合法であることを、状態は新しい状態であることを確認するために、キューに参加することができます
それぞれが状態に変換されるのでBFSは、私は、このコードは、関数にカプセル化されることをお勧めします、の正当性を判断する必要があり、それが大幅にコードの可読性を向上させます。
少し不慣れな会場でマップパートナー:C ++公式文書

概要

BFSは非常に興味深いトピックを使用し、簡単にコードの力は要求しないが、あなたはアイデアを持っている必要があり、コードの後に​​再生する方法を見つけることができます。BFSは、転送や状態の境界条件の中核を把握することで、我々は複雑な問題の簡単なBFSボードを変換することができるようになります。

改善されたポイント

かBFSまたはDFS最終的な分析は、様々な状況を横断する列挙であるが、貪欲以上のアルゴリズムは、時間を節約し、アクセスポイントの数を減らすことができ、これがより少ない時間がかかり、このアルゴリズムのアルゴリズムよりも、しかしよりよいです問題解決のための簡単なビューの競争ポイント、BFSの度合いを実現するためには、実装方法の顔にはまだ良いです時間のかかる被写体が低い必要です。

ソースの問題(C ++)

#include<cstring>
#include<cstdio>
#include<iostream>
#include<map>
#include<queue>
using namespace std;
struct status
{
    /* data */
    int a,b;
    bool operator<(const status &s)const{
        if(a!=s.a) return a<s.a;
        return b<s.b;
    }
    bool operator==(const status &s)const{
		return a==s.a && b==s.b;
	}
};
queue<status> Q;
map<status, status> from;
vector<status> ans;
/* 递归输出方案 */
void print(status &p,int A,int B,int C) 
{
	ans.push_back(p);
	while( from.find(p) != from.end() && (p.a!=0 | p.b!=0))
    {
		p=from[p];
		ans.push_back(p);
    }
	for(int i=ans.size()-1;i>0;i--)
    {
    	status start=ans[i];
    	status end=ans[i-1];
    	if(start.b==end.b)
    	{
    		if(start.a<A && end.a==A)
    		{
    			printf("fill A\n");
			}
			else if(start.a>0 && end.a==0)
			{
				printf("empty A\n");
			}
		}
		else if(start.a==end.a)
		{
			if(start.b<B && end.b==B)
			{
				printf("fill B\n");
			}
			else if(start.b>0 && end.b==0)
			{
				printf("empty B\n");
			}
		}	
		else if(start.a<end.a && start.b>end.b)
		{
			printf("pour B A\n");
		}
		else if(start.a>end.a && start.b<end.b)
		{
			printf("pour A B\n");
		}
	}
	printf("success\n");
}

void refresh(status &s, status &t) 
{
    if ( from.find(t) == from.end() ) 
    { // 特判合法,加入队列
        from[t] = s;
        Q.push(t);
    }
}

void bfs(int A, int B, int C) 
{
	// 起点, 两杯水都空
	status s,t; s.a=0; s.b=0; 
	Q.push(s);

    while (!Q.empty()) 
    {
    	// 取队首
        s = Q.front(); Q.pop();
        // 特判到达终点
        if (s.a == C || s.b == C) {
            print(s,A,B,C); // 输出方案
			while(!Q.empty())
			Q.pop();
			from.clear(); 
            ans.clear();
            return;
        }

        // 倒空 a 杯的水
        if (s.a > 0) {
            t.a = 0;  // 倒空
            t.b = s.b;// b 杯不变
            refresh(s, t);
        }

        // 同理,倒空 b 杯的水
        if (s.b > 0) {
            t.b = 0;  // 倒空
            t.a = s.a;// a 杯不变
            refresh(s, t);
        }

        // a 杯未满,续满 a 杯
        if (s.a < A) 
        {
        	// 续满 a 杯
        	t.a = A;  
        	t.b = s.b;
            refresh(s, t);
        }
        // 同理,b 杯未满,续满 b 杯
        if (s.b < B) 
        {
            //续满 b 杯
            t.a = s.a;
            t.b = B;
            refresh(s, t);
        }

        if (s.b != 0 && s.a<A) 
        {
            if (s.a + s.b <= A) 
            {
                t.a = s.a + s.b;
                t.b = 0;
           		refresh(s, t);
                } else 
            {
                t.a = A;
                t.b = s.a + s.b - A;
            	refresh(s, t);
                }
        }
        if (s.a != 0 && s.b<B) 
        {
            if (s.a + s.b <= B) 
            {
                t.a = 0;
                t.b = s.a + s.b;
                refresh(s, t);
            } else 
            {
                t.a = s.a + s.b - B;
                t.b = B;
                refresh(s, t);
            }
        }
    }
    printf("-1\n");
}
int main() 
{
    int a, b, c; 
    while(cin>>a>>b>>c)
    {
    	bfs(a, b, c);
	}
    return 0;
}/* 26 29 11 */

公開された17元の記事 ウォンの賞賛2 ビュー1664

おすすめ

転載: blog.csdn.net/qq_43942251/article/details/104679179