<p>You are given two jugs with capacities <code>x</code> liters and <code>y</code> liters. You have an infinite water supply. Return whether the total amount of water in both jugs may reach <code>target</code> using the following operations:</p>

<ul>
	<li>Fill either jug completely with water.</li>
	<li>Completely empty either jug.</li>
	<li>Pour water from one jug into another until the receiving jug is full, or the transferring jug is empty.</li>
</ul>

<p>&nbsp;</p>
<p><strong class="example">Example 1: </strong></p>

<div class="example-block" style="border-color: var(--border-tertiary); border-left-width: 2px; color: var(--text-secondary); font-size: .875rem; margin-bottom: 1rem; margin-top: 1rem; overflow: visible; padding-left: 1rem;">
<p><strong>Input: </strong> <span class="example-io" style="font-family: Menlo,sans-serif; font-size: 0.85rem;"> x = 3, y = 5, target = 4 </span></p>

<p><strong>Output: </strong> <span class="example-io" style="font-family: Menlo,sans-serif; font-size: 0.85rem;"> true </span></p>

<p><strong>Explanation:</strong></p>

<p>Follow these steps to reach a total of 4 liters:</p>

<ol>
	<li>Fill the 5-liter jug (0, 5).</li>
	<li>Pour from the 5-liter jug into the 3-liter jug, leaving 2 liters (3, 2).</li>
	<li>Empty the 3-liter jug (0, 2).</li>
	<li>Transfer the 2 liters from the 5-liter jug to the 3-liter jug (2, 0).</li>
	<li>Fill the 5-liter jug again (2, 5).</li>
	<li>Pour from the 5-liter jug into the 3-liter jug until the 3-liter jug is full. This leaves 4 liters in the 5-liter jug (3, 4).</li>
	<li>Empty the 3-liter jug. Now, you have exactly 4 liters in the 5-liter jug (0, 4).</li>
</ol>

<p>Reference: The <a href="https://www.youtube.com/watch?v=BVtQNK_ZUJg&amp;ab_channel=notnek01" target="_blank">Die Hard</a> example.</p>
</div>

<p><strong class="example">Example 2: </strong></p>

<div class="example-block" style="border-color: var(--border-tertiary); border-left-width: 2px; color: var(--text-secondary); font-size: .875rem; margin-bottom: 1rem; margin-top: 1rem; overflow: visible; padding-left: 1rem;">
<p><strong>Input: </strong> <span class="example-io" style="font-family: Menlo,sans-serif; font-size: 0.85rem;"> x = 2, y = 6, target = 5 </span></p>

<p><strong>Output: </strong> <span class="example-io" style="font-family: Menlo,sans-serif; font-size: 0.85rem;"> false </span></p>
</div>

<p><strong class="example">Example 3: </strong></p>

<div class="example-block" style="border-color: var(--border-tertiary); border-left-width: 2px; color: var(--text-secondary); font-size: .875rem; margin-bottom: 1rem; margin-top: 1rem; overflow: visible; padding-left: 1rem;">
<p><strong>Input: </strong> <span class="example-io" style="font-family: Menlo,sans-serif; font-size: 0.85rem;"> x = 1, y = 2, target = 3 </span></p>

<p><strong>Output: </strong> <span class="example-io" style="font-family: Menlo,sans-serif; font-size: 0.85rem;"> true </span></p>

<p><strong>Explanation:</strong> Fill both jugs. The total amount of water in both jugs is equal to 3 now.</p>
</div>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>1 &lt;= x, y, target&nbsp;&lt;= 10<sup>3</sup></code></li>
</ul>

class Solution {
public:
    int _x;
    int _y;

    bool canMeasureWater(int x, int y, int target) 
    {
        // store class variables
        _x = x;
        _y = y;

        // some edge cases
        if (x + y < target) return false;
        if (x + y == target) return true;
        if (x == target || y == target) return true;

        // solution - use recursion to traverse all the possible decisions, 
        // and if a decision results in a previous outcome do not proceed with the recursion

        // keep track of visited nodes
        std::map<std::pair<int,int>, bool> visitedDict;
        
        // do a depth first search
        std::stack<std::pair<int,int>> nodesToCheck;
        nodesToCheck.push(std::pair<int,int>(0,0));
        while(nodesToCheck.size() > 0)
        {
            auto currNode = nodesToCheck.top(); 
            nodesToCheck.pop();

            // node already visited, just remove it from the stack
            if (visitedDict.count(currNode)) continue;

            // new node, add it to the dictionary and the stack
            visitedDict[currNode] = true;

            // check the sum, and quit if success
            auto sum = currNode.first + currNode.second;
            if (sum == target) return true;

            // explore all the possible decisions and add them to the stack
            nodesToCheck.push(Fill1(currNode));
            nodesToCheck.push(Fill2(currNode));
            nodesToCheck.push(Dump1(currNode));
            nodesToCheck.push(Dump2(currNode));
            nodesToCheck.push(Transfer12(currNode));
            nodesToCheck.push(Transfer21(currNode));
        }

        return false;
    }

    // fill the first jug
    std::pair<int,int> Fill1(std::pair<int,int> node)
    {
        return std::pair<int,int>(_x, node.second);
    }

    // fill the second jug
    std::pair<int,int> Fill2(std::pair<int,int> node)
    {
        return std::pair<int,int>(node.first, _y);
    }

    // empty the first jug
    std::pair<int,int> Dump1(std::pair<int,int> node)
    {
        return std::pair<int,int>(0, node.second);
    }
    
    // empty the second jug
    std::pair<int,int> Dump2(std::pair<int,int> node)
    {
        return std::pair<int,int>(node.first, 0);
    }

    std::pair<int,int> Transfer12(std::pair<int,int> node)
    {
        int a = node.first;
        int b = node.second;
        auto maxTransfer = _y - b;
        if (a > maxTransfer)
        {
            // perform the maximum transfer
            b+= maxTransfer;
            a-= maxTransfer;
        }
        else 
        {
            // empty a fully into b
            b+=a;
            a=0;
        }
        return std::pair<int,int>(a,b);
    }

    std::pair<int,int> Transfer21(std::pair<int,int> node)
    {
        int a = node.first;
        int b = node.second;
        auto maxTransfer = _x - a;
        if (b > maxTransfer)
        {
            // perform the maximum transfer
            a+= maxTransfer;
            b-= maxTransfer;
        }
        else 
        {
            // empty b fully into a
            a+=b;
            b=0;
        }
        return std::pair<int,int>(a,b);
    }
};
8600