HDU-4306-mahjong-2-Sat

Source: Internet
Author: User

The original matrix and target matrix are given. Http://acm.hdu.edu.cn/showproblem.php? PID = 1, 4306

Two operations: select a horizontal line to exchange two elements (cost CA ).

Select the two-element exchange (CB) of a column ).

An operation takes only one time.

Q: minimum cost from the original matrix to the target matrix.

Official solution: Let's take a look.

This question needs to be solved using 2-Sat, but it requires some clever construction and basic graph theory knowledge to be successfully converted into a model. At last, we need to pay attention to some details.

First, the first three paragraphs in the question can be ignored directly (even if they are already separated by graphs )..

To solve this problem, we can first construct a proof that a State can reach any state after a maximum of three operations (each operation refers to several operations.
Assume that the operation order is a... AB... ba... A (and vice versa ).
The coordinate of a grid in the source image is (x0, y0), and the coordinate to be transferred to the target is (x1, Y1), then it is clear that the coordinate before the last operation is (x1, Y2 ).
And so on, the transfer path should be: (x0, y0) ---> (x0, Y2) ---> (x1, Y2) ---> (x1, Y1 ), the only path affected is Y2.
Whether this construction method is successful depends on whether it can be converted from (x0, Y2) to (x1, Y2 ).
In other words, the first operation requires that the X1 to be reached for each point in each column be different from each other.
In other words, if we construct a bipartite graph from the original position set x0 of each vertex to its target position set X1, then the construction is successful if we can find N non-Intersecting perfect matches.
Obviously, if each row has n vertices, the degrees of each vertex in the X set are N. Similarly, the degrees of each vertex in the Y set are n.
For any subset of X, its adjacent set in Y is recorded as a (s). Obviously, the degree of S is n | S |, and its adjacent set a (s) the degree must be at least N | S |.
Since each vertex has the same degree of N, it is clear that the image must have a perfect match. | A (s) |> = | S |.
After the match is deleted, the degrees of each point are still equal. Likewise, we can find the next match. Then we can prove the above conclusion.

With the above proof, we can classify and discuss based on the situation.
1. cannot reach
2. direct equivalence
3. One-step access
4. Two steps are reachable.
5. Three-Step access

The first three types can be judged directly. If the last two types can be judged, we will know that the other four types are not satisfied. Note that each judgment must be performed by row and column.
We should consider how to determine the two-step reachable state. We may consider the operations of a... AB... B First (the same is true for the opposite ).
Each vertex (x0, y0) must reach the target point (x1, Y1). Obviously, the path is (x0, y0) ---> (x0, Y1) ---> (x1, Y1 ).
Because each vertex can appear at most twice, each vertex can be selected with a maximum of two groups.
When there is an intersection between the two vertices required by a scheme, it means that the two schemes cannot be selected at the same time.
This is a classic 2-SAT problem and can be solved by using a strong Unicom component or dyeing.

The specific implementation should have some skills. Even the standard implementation method is too naive, and it runs 2 S... Qaq.

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXN = 305;const int MAXM = 100010;struct Edge{    int v, next;} shift[MAXN*MAXN*2], edge[MAXN*MAXN*4];int shiftNumber, edgeNumber;int shiftHead[MAXN*MAXN*2], edgeHead[MAXN*MAXN*2];int a[MAXN][MAXN], b[MAXN][MAXN];int al[MAXN*MAXN], bl[MAXN*MAXN];int ta[MAXN], tb[MAXN];int na[MAXM], nb[MAXM];int pa[MAXM][2], pb[MAXM][2];bool va[MAXM], vb[MAXM];int n, nn, ca, cb;int differ[MAXN*MAXN], differNumber;int maxNumber;bool inStack[MAXN*MAXN*2];int dfn[MAXN*MAXN*2], low[MAXN*MAXN*2];int stack[MAXN*MAXN*2], belong[MAXN*MAXN*2];int top, index, componentNumber;inline int min(int x, int y){    return x < y ? x : y;}inline int max(int x, int y){    return x > y ? x : y;}inline void swap(int &x, int &y){    int temp = x;    x = y;    y = temp;}inline int getPosition(int x, int y){    return x * n + y;}inline int getRow(int pos){    return pos / n;}inline int getColumn(int pos){    return pos % n;}void clearEdges(){    shiftNumber = 0;    edgeNumber = 0;    memset(shiftHead, -1, sizeof(shiftHead));    memset(edgeHead, -1, sizeof(edgeHead));}inline void addShift(int u, int v){    shift[shiftNumber].v = v;    shift[shiftNumber].next = shiftHead[u];    shiftHead[u] = shiftNumber ++;}inline void addEdge(int u, int v){    edge[edgeNumber].v = v;    edge[edgeNumber].next = edgeHead[u];    edgeHead[u] = edgeNumber ++;}void transpose(){    for(int i=0; i<n; ++i)    {        for(int j=i+1; j<n; ++j)        {            swap(a[i][j], a[j][i]);            swap(b[i][j], b[j][i]);        }    }}void getDifference(){    differ[al[0]] = 0;    differNumber = 1;    for(int i=1; i<nn; ++i)    {        if(al[i] != al[i-1])        {            differ[al[i]] = differNumber ++;        }    }}void getNumberPosition(){    memset(na, 0, sizeof(na));    memset(nb, 0, sizeof(nb));    for(int i=0; i<n; ++i)    {        for(int j=0; j<n; ++j)        {            pa[a[i][j]][na[a[i][j]]++] = getPosition(i, j);            pb[b[i][j]][nb[b[i][j]]++] = getPosition(i, j);        }    }}bool isUnreachable(){    sort(al, al + nn);    sort(bl, bl + nn);    for(int i=0; i<nn; ++i)    {        if(al[i] != bl[i])        {            return true;        }    }    return false;}bool isReachableByOneStep(){    for(int i=0; i<n; ++i)    {        for(int j=0; j<n; ++j)        {            ta[j] = a[i][j];            tb[j] = b[i][j];        }        sort(ta, ta + n);        sort(tb, tb + n);        for(int j=0; j<n; ++j)        {            if(ta[j] != tb[j])            {                return false;            }        }    }    return true;}int myStack[MAXN * MAXN * 8];int myStackTop;void push(int x){    myStack[myStackTop ++] = x;}int pop(){    return myStack[-- myStackTop];}bool isEmpty(){    return myStackTop == 0;}void dfs(int x, int depth){    int i, t;    myStackTop = 0;start:    dfn[x] = low[x] = index ++;    inStack[x] = true;    stack[top++] = x;    for(i=edgeHead[x]; i!=-1; i=edge[i].next)    {        if(dfn[edge[i].v] == -1)        {            push(x);            push(depth);            push(i);            push(t);            x = edge[i].v;            depth = depth + 1;            goto start;ret:            low[x] = min(low[x], low[edge[i].v]);        }        else if(inStack[edge[i].v])        {            low[x] = min(low[x] ,dfn[edge[i].v]);        }    }    if(dfn[x] == low[x])    {        do        {            t = stack[--top];            inStack[t] = false;            belong[t] = componentNumber;        }        while(t != x);        ++ componentNumber;    }    if(isEmpty())    {        return;    }    t = pop();    i = pop();    depth = pop();    x = pop();    goto ret;}void tarjan(){    memset(inStack, false, sizeof(inStack));    memset(dfn, -1, sizeof(dfn));    memset(low, -1, sizeof(low));    top = index = componentNumber = 0;    for(int i=0; i<differNumber*2; ++i)    {        if(dfn[i] == -1)        {            dfs(i, 0);        }    }}bool isReachableByTwoStep(){    clearEdges();    for(int i=1; i<=maxNumber; ++i)    {        if(na[i] == 1)        {            addShift(getPosition(getRow(pa[i][0]), getColumn(pb[i][0])), differ[i]<<1);            addShift(getPosition(getRow(pa[i][0]), getColumn(pb[i][0])), (differ[i]<<1) + 1);        }        else if(na[i] == 2)        {            addShift(getPosition(getRow(pa[i][0]), getColumn(pb[i][1])), differ[i]<<1);            addShift(getPosition(getRow(pa[i][0]), getColumn(pb[i][0])), (differ[i]<<1) + 1);            addShift(getPosition(getRow(pa[i][1]), getColumn(pb[i][0])), differ[i]<<1);            addShift(getPosition(getRow(pa[i][1]), getColumn(pb[i][1])), (differ[i]<<1) + 1);        }    }    for(int i=0; i<n; ++i)    {        for(int j=0; j<n; ++j)        {            for(int k=shiftHead[getPosition(i, j)]; k!=-1; k=shift[k].next)            {                for(int l=shift[k].next; l!=-1; l=shift[l].next)                {                    if((shift[k].v ^ 1) == shift[l].v)                    {                        continue;                    }                    addEdge(shift[k].v, shift[l].v ^ 1);                    addEdge(shift[l].v, shift[k].v ^ 1);                }            }        }    }    tarjan();    for(int i=0; i<differNumber; ++i)    {        if(belong[i<<1] == belong[(i<<1)+1])        {            return false;        }    }    return true;}int main(){    int caseNumber;    scanf("%d", &caseNumber);    for(int cas=1; cas<=caseNumber; ++cas)    {        scanf("%d%d%d", &n, &ca, &cb);        nn = n * n;        bool isSame = true;        maxNumber = 0;        for(int i=0,k=0; i<n; ++i)        {            for(int j=0; j<n; ++j)            {                scanf("%d", &a[i][j]);                al[k++] = a[i][j];                maxNumber = max(maxNumber, a[i][j]);            }        }        for(int i=0,k=0; i<n; ++i)        {            for(int j=0; j<n; ++j)            {                scanf("%d", &b[i][j]);                bl[k++] = b[i][j];                if(a[i][j] != b[i][j])                {                    isSame = false;                }            }        }        printf("Case #%d: ", cas);        if(isSame)        {            printf("0\n");        }        else        {            if(isUnreachable())            {                printf("Take off the shoes!\n");            }            else            {                int ans = min(ca * 2 + cb, cb * 2 + ca);                if(isReachableByOneStep())                {                    ans = ca;                }                transpose();                if(ans > cb)                {                    if(isReachableByOneStep())                    {                        ans = cb;                    }                }                if(ans > ca + cb)                {                    getDifference();                    getNumberPosition();                    if(isReachableByTwoStep())                    {                        ans = ca + cb;                    }                    else                    {                        transpose();                        getNumberPosition();                        if(isReachableByTwoStep())                        {                            ans = ca + cb;                        }                    }                }                printf("%d\n", ans);            }        }    }    return 0;}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.