《挑战程序设计竞赛》3.2.2 常用技巧-反转 POJ3276 3279 3185 1222

本文主要是介绍《挑战程序设计竞赛》3.2.2 常用技巧-反转 POJ3276 3279 3185 1222,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

POJ3276

http://poj.org/problem?id=3276

题意

N头牛排成一列1<=N<=5000。每头牛或者向前(表示为F)或者向后(表示为B)。为了让所有牛都面向前方,农夫每次可以将K头连续的牛转向1<=K<=N,求操作的最少次数M和对应的最小K。

思路

所有情况穷举O(2^N)肯定超时。
顺序考虑每头牛的反转方向能不能行呢?因为想改变一头牛的方向就必定影响k头牛,但再思考一下,当一头牛被反转2的倍数次时,与初始方向相同,可视为无反转,所以对于每头牛来说,只有被反转和未反转两种操作。
但我们要枚举的是大小为K的区间的反转,顺序考虑时每个区间的反转状态可以被前面的状态所确定,这时候最坏情况下复杂度O(N^3)。这里可以用sum来记录前面的反转状态和,从而将复杂度降到O(N^2),具体见代码。
此题值得注意的地方:
(1)判断条件很容易出错,需要考虑清楚n和k的所有情况,我因为没写好判断,WA了两次。
(2)这个题中二进制的妙用可在代码中细细体会。
(3)用bool存储似乎能进一步缩减内存使用,当然代码需要同步优化。

代码

Source CodeProblem: 3276       User: liangrx06
Memory: 276K        Time: 360MS
Language: C++       Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;const int N = 5000;int main(void)
{int n;int f[N], t[N];cin >> n;char c[2];for (int i = 0; i < n; i ++) {scanf("%s", c);if (c[0] == 'F')f[i] = 0;elsef[i] = 1;}int ansm = n, ansk = 1;for (int k = 1; k <= n; k ++) {int m = 0;int sum = 0;for (int i = 0; i <= n-k; i ++) {t[i] = (f[i] + sum)&1;m += t[i];sum += t[i];if (i-k+1 >= 0) sum += t[i-k+1];}int flag = 1;for (int i = n-k+1; i < n; i ++) {if ( ((f[i] + sum)&1) == 1)flag = 0;if (i-k+1 >= 0) sum += t[i-k+1];}if (flag == 1 && m < ansm) {ansm = m;ansk = k;}}printf("%d %d\n", ansk, ansm);return 0;
}

POJ3279

http://poj.org/problem?id=3279

题意

一个m*n的01矩阵,每次点击(x,y),那么她的上下左右以及本身就会0变1,1变0,问把矩阵变成全0的,最小需要点击多少步。如果有多个符合条件,求字典序最小的。

思路

枚举第一行翻转情况,2^m,然后验证,由于第一行确定了,后面就可以跟着确定了。
这个题看似思路清晰,实际做的过程中却出了不少错误,比如:
(1)字典序弄反了;
(2)应该验证最后一行,结果想错了;
(3)最优解首先要求的是最小步数,而不是字典序最小,我把顺序弄反了。
代码最终基本和书中例题一样了。

代码

Source CodeProblem: 3279       User: liangrx06
Memory: 248K        Time: 547MS
Language: C++       Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;const int N = 15;int m, n;
int f0[N][N], f[N][N], t[N][N], opt[N][N];
int d[5][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}, {0, 0}};void flip(int i, int j)
{if (t[i][j] == 0) return;for (int k = 0; k < 5; k ++) {int ii = i+d[k][0];int jj = j+d[k][1];if (0 <= ii && ii < m && 0 <= jj && jj < n)f[ii][jj] = (f[ii][jj]+1) & 1;}
}int main(void)
{cin >> m >> n;for (int i = 0; i < m; i ++)for (int j = 0; j < n; j ++)scanf("%d", &f0[i][j]);int minfcount = n*m+1;for (int r = 0; r < (1<<n); r ++) {int fcount = 0;memcpy(f, f0, sizeof(f));for (int j = 0; j < n; j ++) {t[0][n-1-j] = (r>>j)&1;fcount += t[0][n-1-j];flip(0, n-1-j);}for (int i = 1; i < m; i ++) {for (int j = 0; j < n; j ++) {t[i][j] = f[i-1][j];fcount += t[i][j];flip(i, j);/*printf("i=%d, j=%d==========\n", i, j);if (t[i][j]) {for (int ii = 0; ii < m; ii ++)for (int jj = 0; jj < n; jj ++)printf("%d%c", f[ii][jj], (jj == n-1) ? '\n' : ' ');}*/}}bool flag = true;for (int j = 0; j < n; j ++) {if (f[m-1][j] == 1) {flag = false; break;}}if (flag == true && fcount < minfcount) {minfcount = fcount;memcpy(opt, t, sizeof(t));}}if (minfcount == n*m+1)printf("IMPOSSIBLE\n");else {for (int i = 0; i < m; i ++)for (int j = 0; j < n; j ++)printf("%d%c", opt[i][j], (j == n-1) ? '\n' : ' ');}return 0;
}

POJ3185

http://poj.org/problem?id=3185

题意

将一列碗(20个)翻成口朝上,一把下去可能同时反转3个或2个(首尾),求最小翻转次数。

思路

应该说是3276题的简单版,只有两种情况需要考虑:以第一个为中心的反转是否做。后续的反转据此可以确定,然后检验是否符合条件即可。

代码

Source CodeProblem: 3185       User: liangrx06
Memory: 164K        Time: 0MS
Language: C++       Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;const int n = 20;
int f0[n], f[n], t[n];void flip(int x)
{if (!t[x]) return;f[x] = (f[x]+1)&1;if (x > 0) f[x-1] = (f[x-1]+1)&1;if (x < n-1) f[x+1] = (f[x+1]+1)&1;
}int main(void)
{for (int i = 0; i < n; i ++)scanf("%d", &f0[i]);int best = n;for (int k = 0; k < 2; k ++) {memcpy(f, f0, sizeof(f));t[0] = k;int cnt = t[0];flip(0);for (int i = 1; i < n; i ++) {t[i] = f[i-1];cnt += t[i];flip(i);}if (f[n-1] == 0) {best = min(cnt, best);}}printf("%d\n", best);return 0;
}

POJ1222

http://poj.org/problem?id=1222

题意

poj3279的简单版,详见上文。
这个题固定了行列,而且只需要任意求一个答案就可以。

思路

直接把3279代码拿过来稍作修改即可。

代码

Source CodeProblem: 1222       User: liangrx06
Memory: 244K        Time: 16MS
Language: C++       Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;const int N = 6;int m = 5, n = 6;
int f0[N][N], f[N][N], t[N][N], opt[N][N];
int d[5][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}, {0, 0}};void flip(int i, int j)
{if (t[i][j] == 0) return;for (int k = 0; k < 5; k ++) {int ii = i+d[k][0];int jj = j+d[k][1];if (0 <= ii && ii < m && 0 <= jj && jj < n)f[ii][jj] = (f[ii][jj]+1) & 1;}
}int main(void)
{int casecount;cin >> casecount;for (int puzzle = 1; puzzle <= casecount; puzzle ++) {for (int i = 0; i < m; i ++)for (int j = 0; j < n; j ++)scanf("%d", &f0[i][j]);int minfcount = n*m+1;for (int r = 0; r < (1<<n); r ++) {int fcount = 0;memcpy(f, f0, sizeof(f));for (int j = 0; j < n; j ++) {t[0][n-1-j] = (r>>j)&1;fcount += t[0][n-1-j];flip(0, n-1-j);}for (int i = 1; i < m; i ++) {for (int j = 0; j < n; j ++) {t[i][j] = f[i-1][j];fcount += t[i][j];flip(i, j);}}bool flag = true;for (int j = 0; j < n; j ++) {if (f[m-1][j] == 1) {flag = false; break;}}if (flag == true && fcount < minfcount) {minfcount = fcount;memcpy(opt, t, sizeof(t));break;}}printf("PUZZLE #%d\n", puzzle);for (int i = 0; i < m; i ++)for (int j = 0; j < n; j ++)printf("%d%c", opt[i][j], (j == n-1) ? '\n' : ' ');}return 0;
}

这篇关于《挑战程序设计竞赛》3.2.2 常用技巧-反转 POJ3276 3279 3185 1222的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/868683

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

跨国公司撤出在华研发中心的启示:中国IT产业的挑战与机遇

近日,IBM中国宣布撤出在华的两大研发中心,这一决定在IT行业引发了广泛的讨论和关注。跨国公司在华研发中心的撤出,不仅对众多IT从业者的职业发展带来了直接的冲击,也引发了人们对全球化背景下中国IT产业竞争力和未来发展方向的深思。面对这一突如其来的变化,我们应如何看待跨国公司的决策?中国IT人才又该如何应对?中国IT产业将何去何从?本文将围绕这些问题展开探讨。 跨国公司撤出的背景与

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

常用的jdk下载地址

jdk下载地址 安装方式可以看之前的博客: mac安装jdk oracle 版本:https://www.oracle.com/java/technologies/downloads/ Eclipse Temurin版本:https://adoptium.net/zh-CN/temurin/releases/ 阿里版本: github:https://github.com/

购买磨轮平衡机时应该注意什么问题和技巧

在购买磨轮平衡机时,您应该注意以下几个关键点: 平衡精度 平衡精度是衡量平衡机性能的核心指标,直接影响到不平衡量的检测与校准的准确性,从而决定磨轮的振动和噪声水平。高精度的平衡机能显著减少振动和噪声,提高磨削加工的精度。 转速范围 宽广的转速范围意味着平衡机能够处理更多种类的磨轮,适应不同的工作条件和规格要求。 振动监测能力 振动监测能力是评估平衡机性能的重要因素。通过传感器实时监

30常用 Maven 命令

Maven 是一个强大的项目管理和构建工具,它广泛用于 Java 项目的依赖管理、构建流程和插件集成。Maven 的命令行工具提供了大量的命令来帮助开发人员管理项目的生命周期、依赖和插件。以下是 常用 Maven 命令的使用场景及其详细解释。 1. mvn clean 使用场景:清理项目的生成目录,通常用于删除项目中自动生成的文件(如 target/ 目录)。共性规律:清理操作

BUUCTF靶场[web][极客大挑战 2019]Http、[HCTF 2018]admin

目录   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 [web][HCTF 2018]admin 考点:弱密码字典爆破 四种方法:   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 访问环境 老规矩,我们先查看源代码

滚雪球学Java(87):Java事务处理:JDBC的ACID属性与实战技巧!真有两下子!

咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java SE啦,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~ 🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!! 环境说明:Windows 10