[CodeJam 2021 Round 3] Square Free(调整法 / 字典序最小解网络流)
CodeJam 2021 Round3 Square Free
- problem
- solution
- code
- code-std
problem
神奈子是个很爱打麻将的老婆婆,有一天她把她的麻将放进了一个 n×mn\times mn×m 的网格图里,每个麻将可以左斜着放入网格中(如 /
),也可以右斜着(如 \
),如下图所示。不过她还没决定好应该怎么摆。
因为她很喜欢风,所以摆麻将的地方风很大,容易把麻将吹倒,因此存在两个序列 aaa 和 bbb,表示第 iii 行必须有恰好 aia_iai 个麻将左斜,第 jjj 列必须有恰好 bjb_jbj 个麻将左斜,才能保证麻将的稳定性。
因为她很喜欢山,所以她喜欢山一般的参差不齐感,而不希望麻将形成规规整整的正方形(如下图所
示)。
她非常没耐心,所以你需要告诉她能否将麻将摆成符合要求的样子,如果可以,为了节省她的时间,你只需要任意给出一种方案即可 。
n,m≤20n,m\le 20n,m≤20。
solution
20简直就是各种算法和高复杂度爆艹
在考场上的 调整法 竟然过了,我也不知道对不对。 还是分享给大家。
这种给出任意一种方案,一般都是猜结论或者单纯构造。
这里我从构造入手。
先考虑行的限制,每行从第一列开始直接就放 aia_iai 个 /
,剩下的放 \
。每一行形如 //...//\\..\
。
这样首先是将行限制全都满足了,在此基础上继续考虑列的限制。
从左往右每一列每一列的考虑,考虑到第 iii 列的时候,要求前 i−1i-1i−1 列全都已经符合要求。
该列的
/
恰好满足要求那就直接下一列。该列的
/
大于要求。那么就需要将该列上的某几行/
替换成\
。直接枚举每一行 kkk ,然后再枚举 kkk 行后面 j(j>i)j(j>i)j(j>i) 列的情况。
如果 kkk 行 iii 列恰好是
/
,且 kkk 行某个 jjj 列恰好是\
,那么就可以交换两个位置上的字符。kkk 行的限制仍然满足,也没有改动前 i−1i-1i−1 列。
后面列的改变后面调整再说,现在只对前面负责。
该列的
/
小于要求。与上面同理,需要将该列上的某几行\
替换成/
。不赘述。
以上是第一步调整。有可能还不行,就需要进行第二步调整。
以该列的 /
大于要求为例,可能会出现该列上的每个 \
所在行的 ∀j,j>i\forall j,j>i∀j,j>i 列都是 \
。
那么就找不到可以与该位置交换的 /
了。
这个时候就只能动前面的了。
考虑 iii 列的某行 j1j_1j1,该 (j1,i)(j_1,i)(j1,i) 格子字符为 /
,考虑现在将其调整为 \
。
那么首先找到 j1j_1j1 行的 x(x<i)x(x<i)x(x<i) 列,(j1,x)(j_1,x)(j1,x) 格子字符为 /
。
如果这两个交换,则第 iii 列的 /
数量就会减少 111,且 j1j_1j1 行的限制没有破坏。
此时发现,xxx 列的限制破环了,再找一行 j2j_2j2,(j2,x)(j_2,x)(j2,x) 上的字符为 \
,将其改变成 /
,又重新维护了 xxx 列的限制。
又发现 j2j_2j2 行的限制被破坏,又得找一个 yyy 列,继续调整..................
会发现 j2j_2j2 行后面 y(y>i)y(y>i)y(y>i) 列一定有 \
。
因为既然能进入到第二步的调整,那就证明任意行已经找不到 /
。
将其改变为 /
,那么 j2j_2j2 行的限制就又重新维护了。
不管 iii 列以后的事情,那么所有行和前面所有列的限制仍然成立。
以该列的 /
小于要求同理,也不赘述。
两步调整后,会发现,如果只有第一步调整是永远不会出现正方形的,可是有第二步后就不能保证了。
所以进行第三步对正方形的调整。
而且上述调整发现只可能(?)出现边长为 111 的正方形。
因为上述调整是行列从小到大的。
一定是先将上一行想尽办法的调整了再调整下一行,所以不可能下一行又折回去这种感觉。
直接枚举每个位置为左上角格子,然后判断一个 2×22\times 22×2 格子是否构成正方形,如果是那么交换两行,注意此时不能直接往下枚举。
i.e.
/\
/\
\/
有可能换了后跟上面的重新组成了一个正方形,那就行减减,再判断一遍。
最后三步调整后再判断一下是否又正方形的出现,这是还出现就直接判为 IMPOSSIBLE
。
很有可能是因为数据太水,导致我错误地艹过去了。哈哈哈哈
以下就是正解算法。
发现只要存在一个满足行列限制的方案,就一定存在没有正方形的方案。
如果存在正方形,可以将正方形所有格子内的字符全反转,仍然满足行列限制,但破环了正方形。
可以证明这样是不会存在环,无限循环下去的。
证明:
将表格字符压成一维的字符串表示,假设
/
的字典序大于\
。那么每次反转一个正方形后,字典序只会变小。
因此字典序最小的方案一定是不存在正方形的。
问题转化为构造一个字典序最小的方案数。
再加上这个行列限制,明显就是网络流经典问题。
具体可见 code-std
实现。
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;
}
[CodeJam 2021 Round 3] Square Free(调整法 / 字典序最小解网络流)相关推荐
- Hacked Exam-Google Codejam 2021 Round 1A
Hacked Exam-Google Codejam 2021 Round 1A第三题 There is an exam with Q(1 ≤\leq≤ Q ≤\leq≤ 120)true or fa ...
- [CodeJam 2019 Round 3] Rancake Pyramid(笛卡尔树)
CodeJam 2019 Round 3 Rancake Pyramid problem solution code problem 神奈子是个很爱打麻将的老婆婆,有一天她把她的麻将放成了 nnn 堆 ...
- SQL函数之数学函数:ABS,PI,POWER,RAND,ROUND,SQUARE, SQRT,三角函数的用法
数学函数 ABS函数(取绝对值) --ABS(绝对值)函数 SELECT ABS(-5) AS '-5的绝对值', ABS(0) AS '0的绝对值', ABS(5) AS '5的绝对值' PI(圆周 ...
- Codejam Qualification Round 2019
本渣清明节 闲里偷忙 做了一下codejam 水平不出意外的在投稿之后一落千丈 后两题的hidden test竟然都挂了 A. Foregone Solution 水题,稍微判断一下特殊情况(比如10 ...
- 图论--2-SAT--暴力染色法模板(字典序最小解) RQ的板子
//暴力DFS,求字典序最小的解,也是求字典序唯一的方法 #include<cstdio> #include<cstring> #include<vector> u ...
- 「LibreOJ Round #11」Misaka Network 与测试 (网络流跑二分图匹配)
description 研究者们想要测试 Misaka Network,于是他们把 Misaka Network 中的所有妹妹们召集到了一起. 现在妹妹们排成了 N行 M 列,有的位置没有人.现在研究 ...
- 解决了:微信小程序使用canvas绘制倒计时圆圈和数字居中的实现
微信小程序使用canvas绘制倒计时圆圈和数字居中的实现 1.显示结果 2.过程: (1)wxml + css <!-- 每道题 --><view style="backg ...
- svg: svg预定义的形状
SVG 有一些预定义的形状元素,可被开发者使用和操作: 矩形 <rect> 圆形 <circle> 椭圆 <ellipse> 线 <line> 折线 & ...
- HTML添加上传图片并进行预览
使用说明:新建文件,直接复制粘贴,保存文件为html 格式,在浏览器运行即可: 第一种: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Tr ...
最新文章
- Gitlab CI更多内容学习(二)
- EntLib.com Forum/YAF 开源论坛系统!可免费下载!
- Ribbon-2通过代码自定义配置ribbon
- CABasicAnimation fillMode和removedOnCompletion
- python开源项目homeassistant_树莓派安装家庭助理,Homeassistant,HASS
- python 字典 内存_Python 字典(联合内存、联合数组)
- python实战项目前后端分离flask_Flask Vue 构建前后端分离的应用
- html提现页面模板,提现记录.html
- L3-020 至多删三个字符 (30 分) DP
- centos7 yum安装mysql5_Centos7 yum安装mysql5.7
- 【IP分析】合并信号concat,拆分总线slice
- 安卓kotlin教程
- “阿喀琉斯之踵”与“零缺陷”管理
- 一个参数在注塑行业的影响——“停留时间”
- 【华人学者风采】杨义 悉尼科技大学
- jQuery设置select的选中值
- Android 性能专项之 Memory Monitor 工具-memery
- String的xml转map
- 拼多多店铺logo怎么做?
- GTC2019大会的部分总结
热门文章
- oracle cpu 100%原因,oracle 12.1 cpu 100%
- java 接口的静态方法_Java8新特性:接口的默认方法与接口的静态方法
- 机器人J中WPR_优傲:协作机器人的未来在哪里?
- php链表和联表的区别,PHP_浅谈PHP链表数据结构(单链表),链表:是一个有序的列表,但 - phpStudy...
- Java当中迭代器的使用(遍历容器ArrayList, HashSet,HashMap)
- [Nginx]nginx 配置实例-动静分离
- [PAT乙级]1033 旧键盘打字(getline()读入)
- [PAT乙级]1017 A除以B
- lua transliterate实现(lua程序设计10.6练习10.3题)
- 哈工大威海计算机组成原理,哈工大威海计算机组成原理复习.pdf