[Rookie Rookie] UVa10603 State Diagram + Dijkstra Shortest Path

Topic narrative

https://vjudge.net/problem/UVA-10603

      There are three cups with capacities  a , b , c (1≤ a,b,c ≤200). In the initial state, the first two cups ( a, b ) are empty and the third cup ( c ) is full of water. Since the cups are not scaled, each time water is poured from one cup to another, it is not allowed to stop until the first cup is emptied or the second cup is full.

Question: Find the water volume d' that a cup can reach by pouring water for a certain number of times , so that d'd and d' is the largest, and output the minimum total pouring volume required to reach d' .

input sample

The first line is the number of test cases T , and the added T lines each contain four integers a, b, c, d , and the meaning is the same as that described in the title.

2
2 3 4 2

96 97 199 62

Sample output

Output one line per use case, containing two integers: minimum pour and d' .

2 2

9859 62

topic analysis

       Considering the respective water content ( v 0 , v 1 , v 2 ) of the three cups at a certain time as a state, the water content changes through one pour of water, that is, the transition between the two states. Obviously, such a state transition is Directed, such a state transition can be viewed as a directed edge. Note that the problem requires the minimum amount of water pouring ( not the number of pouring water ) required to transfer from the initial state to the target state, so the amount of pouring water can be regarded as the weight of the directed edge. In this way, each state and its transition form a directed graph, and the problem is transformed into finding the target state and calculating the shortest path length between the initial state and the target state.

For example, a =1, b =3, c =6, d =4, the initial state is (0,0,6), there is a path (0,0,6)->(1,0,5)->( 0,1,5)->(1,1,4), the terminal state is (1,1,4), and the amount of water poured is 3.


The Dijkstra algorithm based on the priority queue can be used as the basis to complete the search for the shortest path while building the map.

Algorithms and Implementations

Since the total amount of water is c , when v 0 , v 1 are determined, v 2 = c - v 0 - v 1 , which is also determined, so at most 201*201=40401 states.

When implementing Dijkstra's algorithm, a priority queue can be used to select the unmarked state with the shortest distance to the initial state in O ( logn ) time.

In addition, once it is found that a cup with a water capacity of d has appeared in a certain state , the algorithm can be directly exited. The greedy selection nature of Dijkstra's algorithm ensures that the path length at this time must be the shortest (the amount of water poured must be the smallest).

#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<map>
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
const int maxn=40401,maxd=201;//maxn is the maximum number of states, maxd is the maximum number of target water volumes
int T,c[3],d;//T is the number of samples, c[3] is the capacity of three cups, d is the target water volume
struct Vertex {//The definition of the state is also the definition of the directed graph node
    int v[3];//The amount of water in each of the three cups
    Vertex(int a,int b,int c) {v[0]=a;v[1]=b;v[2]=c;}
};
struct Node {//Node definition in the priority queue
    int v,w;//v is the number of the state, w is the shortest path from the initial state to the state v
    Node(int _v,int _w):v(_v),w(_w) {}
    bool operator<(const Node &node) const {
        return w>node.w;
    }
};
map<int,int> id;//Assign a unique id to each state
vector<Vertex> V;//A collection of states (edges)
int n,dist[maxn],ans[maxd],//n is the total number of states, dist is the distance from each state to the initial state, ans is the minimum pouring amount required for each water holding capacity
dir[6][2]={{0,1},{1,0},{0,2},{2,0},{1,2},{2,1}};//dir means 6 ways to pour water from 3 cups
bool vis[maxn], done[maxd];//vis marks whether the shortest path has been found in each state, done marks whether each water volume has been calculated

void dijkstra(void) {
    id.clear();
    V.clear();
    memset(vis,false,maxn*sizeof(bool));
    memset(done,false,(d+1)*sizeof(bool));
    priority_queue<Node> Q;//Priority queue
    dist[id[c[2]]=n=0]=0;//The distance from the initial state to itself is 0
    if(c[2]<=d) {
        done[c[2]]=true;
        ans[c[2]]=0;
    }
    done[0]=true;ans[0]=0;//Initialization of 0 water volume is very important! ! !
    Q.push(Node(n,dist[n]));//The initial state joins the queue
    V.push_back(Vertex(0,0,c[2]));++n;
    while(!Q.empty()) {
        Node node=Q.top();Q.pop();//The unmarked state with the smallest distance to the initial state is dequeued
        int u=node.v,p[3];//u records the number of the current state
        if(V[u].v[0]==d||V[u].v[1]==d||V[u].v[2]==d) break;//If it has appeared Goal state d then the algorithm ends
        if(vis[u]) continue;//The shortest state has been found to skip
        vis [u] = true;
        for(int i=0;i<6;i++) {//Enumerate 6 ways to pour water
            int x=dir[i][0],y=dir[i][1];//Pour water from cup x to y
            if(!V[u].v[x]||V[u].v[y]==c[y]) continue;//Not considered when x has no water to pour or y is full
            p[0]=V[u].v[0];p[1]=V[u].v[1];p[2]=V[u].v[2];
            int w=min(p[x],c[y]-p[y]);
            p[x]-=w;p[y]+=w;
            int key=1000000*p[0]+1000*p[1]+p[2];//The key value of each state is represented by a maximum of 9 digits, such as key[(1,1,4)]=1001004
            if(id.find(key)==id.end()) {//The uncalculated state is saved and queued
                dist[id[key]=n]=node.w+w;
                Q.push(Node(n,dist[n]));
                V.push_back(Vertex(p[0],p[1],p[2]));++n;
            } else {
                int v=id[key];//Status update distance that has been calculated
                if(vis[v]) continue;
                if(node.w+w<dist[v]) {//Relax operation
                    dist[v]=node.w+w;
                    Q.push(Node(v,dist[v]));
                }
            }
            if(!done[p[x]]) {//The minimum pouring amount required to update the amount of water
                ans[p[x]]=node.w+w;
                done[p[x]]=true;
            } else ans[p[x]]=min(ans[p[x]],node.w+w);
            if(!done[p[y]]) {
                ans[p[y]]=node.w+w;
                done[p[y]]=true;
            } else ans[p[y]]=min(ans[p[y]],node.w+w);
        }
    }
}

int main(void) {
    for(scanf("%d",&T);T--;) {
        scanf("%d%d%d%d",c,c+1,c+2,&d);
        dijkstra();
        while(d>=0&&!done[d]) --d;//Find the first water volume that can be used as the target and output
        printf("%d %d\n",ans[d],d);
    }
    return 0;
}


 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324867214&siteId=291194637