一、反转问题

算法概览:给定一个01串,现有翻转规则:翻转某一个位置时其后面2个位置也会跟着翻转,也就是每次翻转都会翻转3个连续的位置。要将01串全部翻转为0,求最小的翻转次数。形似这类题的问题叫做反转问题,也可以叫开关问题,对于这类题通常有以下的特点,思考一下就可以想到。

1、若某一个位置被翻转了n次,则其实际上被翻转了n%2次,因为翻转2k次相当与没翻转,翻转2k+1次相当于翻转了1次,因为要求最小翻转次数,所以对于某一个位置要么只(主动)翻转一次,要么不(主动)翻转。

2、分析易知翻转的顺序并不影响最终结果。(理解不了可自己举个例子在纸上模拟下)

3、由此,反转问题(也叫开关问题)就转化成求反转区间的集合,常常和枚举一起使用。

POJ 3276

N头牛排列成了一列,每头牛或者向前或者向后站,为了让所有的牛都面向前方,农夫约翰买了一台自动转向的机器,这个机器在购买时就必须设定一个数值K,机器每操作一次恰好使K头连续的牛转向(K头牛分别为当前的牛及其之后的牛,不影响位于它之前的牛,并且每次反转必须是K头牛,不可以少于K头)。请求出为了让所有的牛都能面向前方需要的最少的操作次数M和对应的最小的K。

已知:

1≤N≤5000

sampleinput

N= 7

BBFBFBB(F:面向前方,B:面向后方)

sampleoutput

K= 3

M= 3

(先反转1~3号的三头牛,然后再反转3~5号,最后反转5~7号)

思路:

定义 f[i]:区间[i,i+k-1]进行反转的话就为1,否则为0

区间反转部分很好优化:

在考虑第i头牛时候,如果∑i−1j=(i−K+1)f[j]和为奇数,就说明此时这个牛方向与最初相反。

由于 ∑ij=(i+1)−K+1f[j]=∑i−1j=(i−K+1)f[j]+f[i]-f[i-K+1]

所以这个每一次都可以用常数算出来,时间复杂度O(n^2)

#include<cstdio>

#include<cstring>

#include<iostream>

using name space std;

const int N=5000+10;

int f[N],dir[N],n;

int solve(int k){

int cnt=0,sum=0;//sum为f的和

memset(f,0,sizeof(f));

for(int i=1;i<=n-k+1;i++){

if((dir[i]+sum)%2){

cnt++;

f[i]=1;

}

sum+=f[i];

if(i-k+1>=1) sum-=f[i-k+1];

}

for(int i=n-k+2;i<=n;i++){//检查剩下的牛有没有朝后面的情况

if((dir[i]+sum)%2) return n+1;

if(i-k+1>=1) sum-=f[i-k+1];

}

return cnt;

}

int main(){

while(~scanf("%d",&n)){

for(int i=1;i<=n;i++){

char c;scanf(" %c",&c);

if(c=='B') dir[i]=1;

}

int ansk,ansm=n,t;

for(int i=1;i<=n;i++){

t=solve(i);

if(t<ansm){

ansm=t;ansk=i;

}

}

printf("%d %d\n",ansk,ansm);

}

}

POJ 3279

农夫约翰知道聪明的牛产奶多。于是为了提高牛的智商他准备了如下游戏。有一个M×N 的格子,每个格子可以翻转正反面,它们一面是黑色,另一面是白色。黑色的格子翻转后就是白色,白色的格子翻转过来则是黑色。游戏要做的就是把所有的格子都翻转成白色。不过因为牛蹄很大,所以每次翻转一个格子时,与它上下左右相邻接的格子也会被翻转。因为翻格子太麻烦了,所以牛都想通过尽可能少的次数把所有格子都翻成白色。现在给定了每个格子的颜色,请求出用最小步数完成时每个格子翻转的次数。最小步数的解有多个时,输出字典序最小的一组。解不存在的话,则输出IMPOSSIBLE。

已知:

1≤M,N≤15

sample input

M= 4

N= 4 每个格子的颜色如下:(0表示白色,1表示黑色)

10 0 1

01 1 0

01 1 0

10 0 1

sample output

00 0 0

10 0 1

10 0 1

00 0 0

思路:在上面的那道题,让最左端的奶牛反转的情况只有一种,于是直接判断的方法就可以确定,但是这里不一样,比如,看最左上面的角,除了反转(1,1),(1,2),(2,1)都可以导致他翻装。

于是不妨我们先确定最上面一行的反装方式,此时能反转(1,1)只有(2,1),

所以如果已知第一行就可以知道第二行那些点需要反转。这样反复下去,只要最后一行全部为白,就说明可行。

那么这个算法时间复杂度是(N*M*2^N).

#include<cstdio>

#include<cstring>

using name space std;

const int dx[5]={-1,0,0,0,1};

const int dy[5]={0,-1,0,1,0};

int m,n,M[20][20],tmp[20][20],ans[20][20],cnt;

int get(int x,int y){

int t=M[x][y];

for(int i=0;i<5;i++){

int tx=dx[i]+x,ty=dy[i]+y;

if(tx>=0&&tx<m&&ty>=0&&ty<n)t+=tmp[tx][ty];

}

return t%2;

}

int cal(){

for(int i=1;i<m;i++){

for(int j=0;j<n;j++){

if(get(i-1,j)) tmp[i][j]=1;

}

}

for(int j=0;j<n;j++){

if(get(m-1,j)!=0) return n*m+1;

}

int res=0;

for(int i=0;i<m;i++){

for(int j=0;j<n;j++){

res+=tmp[i][j];

}

}

return res;

}

int main(){

while(~scanf("%d%d",&m,&n)){

cnt=n*m+1;

for(int i=0;i<m;i++){

for(int j=0;j<n;j++){

scanf("%d",&M[i][j]);

}

}

for(int i=0;i<(1<<n);i++){

memset(tmp,0,sizeof(tmp));

for(int j=0;j<n;j++){

tmp[0][j]=i>>j&1;

}

int t=cal();

if(t<cnt){

cnt=t;

memcpy(ans,tmp,sizeof(tmp));

}

}

if(cnt==n*m+1){

printf("IMPOSSIBLE\n");

}

else{

for(int i=0;i<m;i++){

for(int j=0;j<n;j++){

printf("%d%c",ans[i][j],j+1==n ? '\n':' ');

}

}

}

}

}

POJ 3185

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

思路:这题分析一下,可以知道选择从第一个开始翻,还是聪第二个开始翻,会导致两种不同的状态和结果,但都是唯一的。所以就枚举第一个还是第二个开始翻,然后从左往右依次判断,接下来每个点需不需要翻转取决它左边是不是朝下。

#include<cstdio>

#include<cstring>

#include<algorithm>

using name space std;

int dir[25],f[25];

int main(){

while(~scanf("%d",&dir[0])){

int tmp=0,ans=20;

memset(f,0,sizeof(f));

for(int i=1;i<20;i++)scanf("%d",&dir[i]);

f[0]=1;tmp++;

for(int i=1;i<20;i++){

if(f[i]=(f[i-2]^f[i-1]^dir[i-1]))tmp++;

}

if((f[18]^f[19]^dir[19])==0&&tmp<ans) ans=tmp;

tmp=0;f[0]=0;

for(int i=1;i<20;i++){

if(f[i]=(f[i-2]^f[i-1]^dir[i-1]))tmp++;

}

if(f[18]^f[19]^dir[19]==0&&tmp<ans) ans=tmp;

printf("%d\n",ans);

}

}

总结:往往反转问题(开关问题)可以转换成矩阵求解一组方程的解是否存在,用高斯消元求解,并且通过这些分析知道,当自由变员不超过N个时候,也可以用来求解最优解。

二、弹性碰撞

在理想情况下,物体碰撞后,形变能够恢复,不发热、发声,没有动能损失,这种碰撞称为弹性碰撞(elastic collision),又称完全弹性碰撞。生活中,硬质木球或钢球发生碰撞时,动能的损失很小,可以忽略不计,通常也可以将它们的碰撞看成弹性碰撞。

发生弹性碰撞后,两个物体在碰撞后相比碰撞前,相对速度大小相等方向相反;两个物体在发生弹性碰撞前后,动量的矢量和、能量的和都不变;如果两个物体质量相同,速度大小方向都互换,相当于未碰撞。

用N个半径为R厘米的球进行如下实验。

在H米高的位置设置一个圆筒,将求垂直放入(从下向上数第i个球的底端距离地面高度为H + 2R)。实验开始时最下面的球开始掉落,此后每一秒又有一个球开始掉落。不计空气阻力,并假设球与球或地面间的碰撞时弹性碰撞。

请求出实验开始后T秒时每个球底端的高度。假设重力加速度为g=10m/s2

已知:

1≤N≤100

1≤H≤10000

1≤R≤100

1≤T≤10000

sample input

N= 1

H= 10

R= 10

T= 100

sample output

4.95

从高位H的位置下落的话需要花费的时间:

因此,在时刻T时,令K 为满足kt≤T的最大整数,那么

当R = 0时,如果认为球是一样的,就可以忽视他们的碰撞,视为直接互相穿过继续运动。由于在有碰撞时球的顺序不会发生改变,所以忽略碰撞,将计算得到的坐标进行排序后,就能知道每个球的最终位置。

那么,R>0是要怎么样?这种情况下的处理方法基本相同,对于下方开始的第i个球,在按照R = 0计算的结果上加上2*R*i就可以了。

#include<iostream>

#include<cstdio>

#include<cmath>

#include<algorithm>

#include<cstring>

#include<string>

#define sf scanf

#define pf printf

using name space std;

const int Maxn = 110;

double ans[Maxn];

int main()

{

int cas,N,H,R,T,g = 10;

sf("%d",&cas);

while(cas--)

{

sf("%d%d%d%d",&N,&H,&R,&T);

for(int i = 0;i < N;i ++)

{

double t = sqrt(2.0 * H / g);

int k = floor(T / t);

if(k < 0)

ans[i] = H;

else

{

if(k & 1)

ans[i] = H - 0.5 * g * (t -(T - k * t)) * (t - (T - k * t));

else

ans[i] = H - 0.5 * g * (T -k * t) * (T - k * t);

}

T --;

}

sort(ans,ans + N);

for(int i = 0;i < N;i ++)

pf("%.2lf%c",ans[i] + 2.0* R * i / 100,i + 1 == N ? '\n':' ');

}

return 0;

}

/*

2

110 10 100

210 10 100

*/

POJ 1852

题意:在一根长为L的水平木棍上有一群数量为n的蚂蚁,它们以每秒1cm/s的速度走到木棍一端就会掉下去。现在知道它们的起始位置是距离木根左端点的x处。但是不知道它们爬行的方向。在相向而行的两只蚂蚁相遇后,它们会掉头往反方向走。问所有蚂蚁都落下木棍的最快时间和最慢时间。

题解:一开始觉得可以暴搜,每只蚂蚁只有两种情况,不过掉头的事情感觉很复杂。时间复杂度为2的n次幂。肯定超时。  因为是同时出发的,相遇时的两只蚂蚁用的时间是相同的,我们可以无视蚂蚁的区别,当两只蚂蚁相遇时它们保持原样交错而行。这样每只蚂蚁都是独立运动的,那么只要找每只蚂蚁掉下去的时间就行了。

#include<cstdio>

#define maxn 1000100

int a[maxn],ansmin,ansmax,L,n;

int MIN(int a,int b)

{

return a<b?a:b;

}

intMAX(int a,int b)

{

return a>b?a:b;

}

void ansMIN()

{

int i,min;

ansmin=-1;

for(i=0;i<n;++i)

{

min=MIN(a[i],L-a[i]);

if(min>ansmin)

ansmin=min;

}

printf("%d ",ansmin);

}

void ansMAX()

{

int i,max;

ansmax=-1;

for(i=0;i<n;++i)

{

max=MAX(a[i],L-a[i]);

if(max>ansmax)

ansmax=max;

}

printf("%d\n",ansmax);

}

int main()

{

int i,t;

scanf("%d",&t);

while(t--)

{

scanf("%d%d",&L,&n);

for(i=0;i<n;++i)

scanf("%d",&a[i]);

ansMIN();

//求所有蚂蚁掉下去的最短时间

ansMAX();

//求所有蚂蚁掉下去的最长时间

}

return 0;

}

NOIP大纲整理:(十六)反转问题与弹性碰撞相关推荐

  1. Python学习笔记整理(十六)类的设计

    如何使用类来对有用的对象进行建模? 一.Python和OOP Python和OOP实现可以概括为三个概念. 继承     继承是基于Python中属性查找(在X.name表达式中) 多态     在X ...

  2. NOIP大纲整理:(零)历年2000-2016NOIP提高组题目分析

    年份 题目名称 考查内容 难度   2000-2016年NOIP提高组复赛题目 2000-A 进制转换 初等代数,找规律 ★ 2000-B 乘积最大 资源分配DP ★★★ 2000-C 单词接龙 DF ...

  3. 整理第十六届全国大学智能车竞赛比赛数据

    简 介: 整理提交了第十六届全国大学生智能车总决赛的数据. 关键词: 智能车竞赛,总决赛 #mermaid-svg-QA3wJFTY8KGVWeUO {font-family:"trebuc ...

  4. 从零开始自制实现WebServer(十六)---- 学习新工具CMake自动编写MakeFile 分门别类整理源文件心情愉悦

    文章目录 全流程实现博客链接 前引 (十六)---- 学习新工具CMake自动编写MakeFile 小改小动项目接近尾声 1.学习新工具 cmake / shell脚本 需要耐心与时间 2.分门别类整 ...

  5. C++ Primer plus学习笔记-第十六章:string类和标准模板库

    第十六章:string类和标准模板库 前言:这一章已经相当靠近全书的后面部分了:这一章我们会深入探讨一些技术上的细节,比如string的具体构造函数,比如适用于string类的几个函数,比如我们还会介 ...

  6. NeHe OpenGL教程 第二十六课:反射

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  7. 第七十六章 SQL命令 TOP

    文章目录 第七十六章 SQL命令 TOP 大纲 参数 描述 TOP int值 TOP和缓存查询 TOP和ORDER BY TOP 优化 TOP与聚合和函数 示例 第七十六章 SQL命令 TOP 指定返 ...

  8. abbex 区块链学院如何交易之 第十六章 交易计划

    第十六章 交易计划 Abbex 规则运用的铺垫没有一个交易计划,再好的规则也无从施展.怎样给自己制定完善的交易计划?幽灵没有忘记弥补这个重要的环节. 幽灵决定,把在<期货杂志>论坛发表的内 ...

  9. 十六届智能车全向组硬件开源 | 上海海事大学全向行进组

    简 介: 卓大,不知道你能不能看到我的消息.今年是我做车的第三年了,也是最后一年了.三年里经历了许多,走了很多弯路,心里的感慨也不少.这两天在整理资料的时候顺手在CSDN上写了一篇全向组的硬件开源贴, ...

最新文章

  1. asp.net利用Web Service实现短信发送致手机
  2. js联动清除的一个想法
  3. VS2010集成Qt5.2环境搭建
  4. 【IT资讯】年薪170万码农征友,条件让网友炸锅……
  5. python写机器人程序_用Python写的一个多线程机器人聊天程序
  6. java 配置参数_给你的JAVA程序配置参数(Properties的使用)
  7. 关于dev无法更新、调试的问题
  8. [视频]Google Chrome背后的故事
  9. 管理项目的问题跟踪器的提示
  10. linux 进程0 写时复制,linux 写时复制 COW 过程梳理
  11. 洛谷 P4017 最大食物链计数
  12. python的os库的remove可以删除只带有只读属性的_扩展库os中的方法remove()可以删除带有只读属性的文件。(2.0分)_学小易找答案...
  13. 音频频谱特效 jaVa_基于Matlab dsp工具箱 的实时音频采集及频谱显示
  14. Eclipse基础--java环境变量设置
  15. 2022-2028全球与中国移动卫星通信市场现状及未来发展趋势
  16. Anaconda下载(Windows系统)
  17. [算法笔记]NPC问题证明sample
  18. cmd net use 命令
  19. 计算机win7启动不起来,详解电脑启动不了怎么办
  20. 健身房训练计划—背部

热门文章

  1. Android手机省电指南
  2. 投资理财-要有家国情怀
  3. akoj-1270-LOL之盲僧GANK
  4. 【MySQL】误操作使用reset slave怎么办
  5. 几个比较常用的数学函数
  6. JVM中工具jstat的使用
  7. python获取季度函数_有时间列的数据,按季度提取数据,按自己的理解编写的一种方法...
  8. vue项目分割字符串
  9. 立足互联网保险发展趋势,元保保险提出未来发展新思路
  10. Android 10 HAL 层添加HIDL实现过程