[CodeJam 2021 Round 3] Square Free

problem

Shinaiko is an old woman who loves playing mahjong. One day she put her mahjong into a n × m n\times m n × In the grid diagram of m, each mahjong can be placed in the grid obliquely to the left (e.g. /) or obliquely to the right (e.g. \), as shown in the following figure. But she hasn't decided how to put it.

Because she likes the wind very much, the place where mahjong is placed is very windy, which is easy to blow mahjong down, so there are two sequences a a a and b b b. Represents the second i i Line i must have exactly a i a_i ai , mahjong left oblique, second j j Column j must have exactly b j b_j bj# one mahjong is inclined to the left to ensure the stability of mahjong.

Because she likes mountains very much, she likes the uneven feeling of mountains, and doesn't want mahjong to form a regular square (as shown in the figure below)
Shown).

She is very impatient, so you need to tell her whether you can put mahjong in a satisfactory way. If you can, in order to save her time, you just need to give any scheme.

n , m ≤ 20 n,m\le 20 n,m≤20.

solution

20 is simply a variety of algorithms and high complexity

The adjustment method in the examination room has passed, and I don't know if it's right. Or share it with you.

This method gives any scheme, which is generally guessing the conclusion or simple construction.

Here I start with the structure.

First consider the row restrictions. Each row is placed directly from the first column a i a_i ai /, the rest will be put into \. Each line is shaped like / /... / / \ \.. \.

In this way, first of all, the row restrictions are met, and on this basis, continue to consider the column restrictions.

Each column from left to right, considering the second column i i When column i is required, before i − 1 i-1 Train i − 1 has all met the requirements.

  • If the / of this column just meets the requirements, go directly to the next column.

  • The / of this column is greater than the requirement. Then you need to replace some rows / on this column with \.

    Enumerate each row directly k k k. Then enumerate k k After line k j ( j > i ) j(j>i) J (J > I).

    If k k k line i i Column i happens to be /, and k k k line a j j If the j column happens to be \, the characters in the two positions can be exchanged.

    k k The k-line limit is still met and has not been changed before i − 1 i-1 i − 1 column.

    For the changes in the following columns, we will adjust them later. Now we are only responsible for the front.

  • The / of this column is less than the requirement. Similarly to the above, you need to replace some rows \ on this column with /. Don't repeat.

The above is the first step of adjustment. It may not work yet, so the second step needs to be adjusted.

Take the / greater than requirement of this column as an example, the value of each \ row on this column may appear ∀ j , j > i \forall j,j>i ∀ J, J > I columns are \.

Then there is no / that can be exchanged with this location.

At this time, you can only move the front.

consider i i A row in column i j 1 j_1 j1, the ( j 1 , i ) (j_1,i) (j1, i) the grid character is /, consider adjusting it to \.

So first find j 1 j_1 j1} line x ( x < i ) x(x<i) Column x (x < I), ( j 1 , x ) (j_1,x) (j1, x) the grid character is /.

If the two are exchanged, the second i i The / number of columns i will be reduced 1 1 1, and j 1 j_1 The restriction of the j1} line is not broken.

At this point, x x The limit of column x is broken. Find another row j 2 j_2 j2​, ( j 2 , x ) (j_2,x) The character on (j2, x) is \, which is changed to /, and maintained again x x x column limit.

Again found j 2 j_2 The restriction of j2 # line is broken, so we have to find another one y y Column y, continue adjusting . . . . . . ...... ......

Will find j 2 j_2 j2. After line y ( y > i ) y(y>i) Column y (Y > I) must have \.

Since you can enter the second step of adjustment, it proves that any line cannot be found /.

Change it to /, then j 2 j_2 The restriction of j2} line is maintained again.

No matter i i After column i, the restrictions on all rows and all previous columns are still valid.

In the same way as the / less requirement of this column, it is not repeated.

After two-step adjustment, you will find that if only the first step is adjusted, there will never be a square, but it can not be guaranteed after the second step.

So the third step is to adjust the square.

Moreover, it is found that only (?) with side length of 1 1 1 square.

Because the above adjustment is from small to large.

You must try your best to adjust the previous line before adjusting the next line, so it's impossible to fold back the next line.

Directly enumerate each position as the upper left grid, and then judge one 2 × 2 2\times 2 two × 2 whether the grid forms a square. If so, exchange two lines. Note that you can't enumerate directly down at this time.

i.e.

/\
/\
\/

It's possible to change the one above the heel to form a square. Then subtract and judge again.

After the last three steps of adjustment, judge whether the square appears again. If it still appears, it is directly judged as IMPOSSIBLE.

It's probably because the data is too watery, which led me to fuck it by mistake. Ha ha ha ha

The following is the positive solution algorithm.

It is found that as long as there is a scheme that meets the row and column limit, there must be a scheme without square.

If there is a square, the characters in all squares can be reversed, which still meets the row and column limit, but the ring breaks the square.

It can be proved that there will be no ring and infinite cycle.

prove:

Compress the table characters into a one-dimensional string representation, assuming that the dictionary order of / is greater than \.

Then every time you reverse a square, the dictionary order will only become smaller.

Therefore, the scheme with the smallest dictionary order must have no square.

The problem is transformed into constructing a scheme number with the smallest dictionary order.

Coupled with this row and column limit, it is obviously a classic problem of network flow.

See the code STD implementation for details.

code

#include <cstdio>
#include <iostream>
using namespace std;
#define maxn 25
int n, m;
int r[maxn], c[maxn];
//int ROW[maxn], COL[maxn];
int ans[maxn][maxn];

int main() {
    freopen( "net.in", "r", stdin );
    freopen( "net.out", "w", stdout );
    scanf( "%d %d", &n, &m );
    for( int i = 1;i <= n;i ++ ) scanf( "%d", &r[i] );
    for( int i = 1;i <= m;i ++ ) scanf( "%d", &c[i] );
    for( int i = 1;i <= n;i ++ )
        for( int j = 1;j <= r[i];j ++ )
            ans[i][j] = 1;
    for( int j = 1;j <= m;j ++ ) {
        int cnt = 0;
        for( int i = 1;i <= n;i ++ )
            cnt += ans[i][j];
        if( cnt == c[j] ) continue;
        if( cnt > c[j] ) {
            for( int i = 1;i <= n and cnt != c[j];i ++ )
                if( ans[i][j] ) {
                    for( int k = m;k > j;k -- )
                        if( ! ans[i][k] ) {
                            swap( ans[i][j], ans[i][k] );
                            cnt --;
                            break;
                        }
                }
            for( int i = 1;i <= n and cnt != c[j];i ++ )
                if( ans[i][j] ) {
                    for( int k = 1;k <= n;k ++ ) {
                        for( int w = j - 1;w and i != k;w -- )
                            if( ans[k][w] and ! ans[i][w] )
                                for( int x = m;x > j;x -- )
                                    if( ! ans[k][x] ) {
                                        cnt --;
                                        ans[i][j] = 0;
                                        ans[i][w] = 1;
                                        ans[k][w] = 0;
                                        ans[k][x] = 1;
                                        goto nxtj;
                                    }
                    }
                    nxtj:;
                }
        }
        else {
            for( int i = 1;i <= n and cnt != c[j];i ++ )
                if( ! ans[i][j] ) {
                    for( int k = m;k > j;k -- )
                        if( ans[i][k] ) {
                            swap( ans[i][j], ans[i][k] );
                            cnt ++;
                            break;
                        }
                }
            for( int i = 1;i <= n and cnt != c[j];i ++ )
                if( ! ans[i][j] ) {
                    for( int k = 1;k <= n;k ++ ) {
                        for( int w = j - 1;w and i != k;w -- )
                            if( ans[i][w] and ! ans [k][w] )
                                for( int x = m;x > j;x -- )
                                    if( ans[k][x] ) {
                                        cnt ++;
                                        ans[i][j] = 1;
                                        ans[i][w] = 0;
                                        ans[k][w] = 1;
                                        ans[k][x] = 0;
                                        goto nxti;
                                    }
                    }
                    nxti :;
                }
        }
        // printf( "START: %d\n", j );
        // for( int i = 1;i <= n;i ++ ) {
        //     for( int j = 1;j <= m;j ++ )
        //         if( ans[i][j] ) printf( "%c", 47 );
        //         else printf( "%c", 92 );
        //     puts("");
        // }
        if( cnt != c[j] ) return ! printf( "IMPOSSIBLE\n" );
    }
    for( int i = 1;i < n;i ++ )
        for( int j = 1;j < m;j ++ )
            if( ans[i][j] and ! ans[i][j + 1] and ! ans[i + 1][j] and ans[i + 1][j + 1] ) {
                swap( ans[i][j], ans[i + 1][j] );
                swap( ans[i][j + 1], ans[i + 1][j + 1] );
                i -= 2;
                break;
            }
    for( int i = 1;i < n;i ++ )
        for( int j = 1;j < m;j ++ )
            if( ans[i][j] and ! ans[i][j + 1] and ! ans[i + 1][j] and ans[i + 1][j + 1] )
                return ! printf( "IMPOSSIBLE\n" );
    printf( "POSSIBLE\n" );
    for( int i = 1;i <= n;i ++ ) {
        for( int j = 1;j <= m;j ++ )
            if( ans[i][j] ) printf( "%c", 47 );
            // ROW[i] ++, COL[j] ++;
            else printf( "%c", 92 );
        puts("");
    }
    // for( int i = 1;i <= n;i ++ ) if( ROW[i] != r[i] ) return ! printf( "WA\n" );
    // for( int i = 1;i <= m;i ++ ) if( COL[i] != c[i] ) return ! printf( "WA\n" );
    return 0;
}

code-std

#include <bits/stdc++.h>
using namespace std;
#define maxn 25
int a[maxn], b[maxn], r[maxn], c[maxn];
int n, m;

bool check( int x, int y ) {
    memcpy( r, a, sizeof( a ) );
    memcpy( c, b, sizeof( b ) );
    for( int i = x;i <= n;i ++ ) {
        vector < pair < int, int > > v;
        for( int j = ( i == x ? y : 1 );j <= m;j ++ )
            v.push_back( { b[j], j } );
        sort( v.begin(), v.end() );
        for( int k = v.size() - 1;~ k and a[i];k -- )
            a[i] --, b[v[k].second] --;
    }
    bool flag = 1;
    for( int i = 1;i <= n;i ++ ) flag &= a[i] == 0;
    for( int i = 1;i <= m;i ++ ) flag &= b[i] == 0;
    memcpy( a, r, sizeof( r ) );
    memcpy( b, c, sizeof( c ) );
    return flag;
}

int main() {
    scanf( "%d %d", &n, &m );
    int sum = 0;
    for( int i = 1;i <= n;i ++ ) scanf( "%d", &a[i] ), sum += a[i];
    for( int i = 1;i <= m;i ++ ) scanf( "%d", &b[i] ), sum -= b[i];
    if( sum ) return ! puts( "IMPOSSIBLE" );
    if( ! check( 1, 1 ) ) return ! puts( "IMPOSSIBLE" );
    puts( "POSSIBLE" );
    for( int i = 1;i <= n;i ++ ) {
        for( int j = 1;j <= m;j ++ )
            if( check( i, j + 1 ) ) printf( "\\" );
            else a[i] --, b[j] --, printf( "/" );
        puts("");
    }
    return 0;
}

Tags: Graph Theory network-flows

Posted on Tue, 16 Nov 2021 09:18:29 -0500 by egalp