程序设计竞赛题目.docx

上传人:b****8 文档编号:27915196 上传时间:2023-07-06 格式:DOCX 页数:13 大小:142.10KB
下载 相关 举报
程序设计竞赛题目.docx_第1页
第1页 / 共13页
程序设计竞赛题目.docx_第2页
第2页 / 共13页
程序设计竞赛题目.docx_第3页
第3页 / 共13页
程序设计竞赛题目.docx_第4页
第4页 / 共13页
程序设计竞赛题目.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

程序设计竞赛题目.docx

《程序设计竞赛题目.docx》由会员分享,可在线阅读,更多相关《程序设计竞赛题目.docx(13页珍藏版)》请在冰豆网上搜索。

程序设计竞赛题目.docx

程序设计竞赛题目

 

NEERC2006

ProblemA:

ASCIIArt

[Description]

在w*h网格平面内,按顺时针给出一个含n个顶点且都在格点上的简单多边形(不自交),统计每个格子被覆盖的面积的状况.(w,h,n<=100)

[Solution]

枚举指定的格子,再与多边形求交比较麻烦,复杂度也高.实际上,可以对多边形的面积进行梯形剖分,即每条边的端点向x轴做投影,投影点与端点组成的梯形有向面积之和,就可得原面积.由于题目中是按顺时针输入的,则从右向左的有向线段对应的梯形面积为负,从左向右则为正.如左图,对于三角形ABC,其面积为=-AEDB(Green)+BDFC(All)-CFEA(Red).

接下来处理每个梯形,枚举被梯形覆盖的每列格子,按列分别处理.对于每列,一定存在被线段穿过的格子的连续段,如右图的Yellow部分;它的下面都是被完全覆盖的,如右图的Red部分.可以直接处理掉Red部分.对于每一个Yellow部分中的格子,实际上就是做一个规模为4的平面交,若不考虑特殊性,本质上只有以下2种情况(对边,邻边),讨论一下即可.实际上,我不想那么麻烦,写了个凸包算面积.

总复杂度为O(n*w*h).

ProblemB:

BillingTables

[Description]

电话号码为11位的数字串,按优先级给定一系列区间,每个区间有一个标志.若一个电话号码在被某个区间包含(多个,则取优先级高的),则电话号码就具有该区间的标志.现在要求输出用前缀表示的带标志序列.使得电话号码的前缀被匹配,则电话号码就一定具有该前缀的标志.

[Solution]

本质上是输出一棵电话号码的Trie树的叶子.每个结点表示一个电话号码前缀,若某个结点被一个区间完全包含或被几个标志一样的区间完全包含,则作为一个叶子结点,否则继续扩展.最后输出所有叶子结点即可.

每次检查结点是否被包含,需要O(n)时间.总复杂度为O(Ans*n),Ans为叶子总数.

ProblemC:

CellularAutomaton

[Description]

给定一个长度为n的序列A.定义一种操作,使得操作后的序列A'满足:

即A'i为所有和i的圆距离不超过d的元素Aj之和.问经过k次操作后的序列.(n<=500,k<=10000000,m<=1000000,d<=n/2)

[Solution]

每次操作,等价于一个矩阵乘法

:

其中n*n矩阵M为:

(上面例子中的矩阵是d=1的情况)

这样答案就是

其中矩阵的幂运算可以用倍增法在O(logk)次矩阵乘法下得出.然而每次O(n^3)的矩阵乘法还是太慢,需要改进.观察矩阵M的特殊性:

第二行是第一行右移一位,第三行是第二行右移一位,...,等等.即上行右移一位为下行.设第一行为x1,x2,...,xn,则矩阵M可以写为:

同样的,对于列也一样,左行下移一位为右行.设第一列为y1,y2,...,yn,则矩阵M可以写为:

称这样的性质为循环矩阵.易知以上两种表示法是同构的,考察两种表示法相乘的结果:

结果依然是一个循环矩阵,即一个循环矩阵乘循环矩阵还是循环矩阵.于是只要记录矩阵的第一行或第一列就可以得到整个矩阵,就是说每次乘法只要算出结果的第一行或第一列即可.乘法的时间降为O(n^2).总复杂度为O(n^2logk)

ProblemD:

DrivingDirections

[Description]

在平面上有n个平行于坐标轴的矩形障碍物,现需要将一个半径为r的圆从A点移动到B点.求最短路.(n<=30)

[Solution]

将圆靠着矩形滑动(相切),圆心的轨迹形成了一个导圆角矩形.导圆角矩形是由原矩形的4条边向外平移一个半径的距离,加上4个1/4圆作为导角.导圆角矩形的内部圆心无法进入.问题转化成,在若干导圆角矩形的障碍下,一个点移动到另一个点的最短路.

由于在曲线上点是连续的,无法使用图论算法,所以需要根据最短路的性质进行点的离散化,建立带权图.

(1)边上的点:

如下图,粗蓝色代表导圆角矩形上的完整的直线段.对于另外一个不在导圆角矩形内部的任意一点D,由三角形的性质,得到AD或CD一定比ABD,CBD短.这就说明了在直线段上除了端点A,C,没必要有其他点作为离散点.

(2)弧上的点

(2.1)如下图,对于在另一个导圆角矩形上的弧l,与弧AB的相切,切线段为CD,C,D分别为两段弧上的切点.C,D都应作为离散点.因为从A到l的最短路必经过C,D,且C,D为该路径上离开或进入导圆角矩形的事件点.

(2.2)如下图,对于不在导圆角矩形内部的任意一点D,D与弧AB相切于C.C应作为离散点.因为从B到D的路径只有过C点的路径最短,且C为离开导圆角矩形的事件点.

(2.2)

由于(2.1)会产生O(n^2)个离散点,O(n^2)条边;接着(2.2)会在(2.1)的基础上产生(n^3)的离散点,O(n^3)条边.实际上,在(2.1)中,点和边是共生的,即在产生边的过程中,若该边与障碍相交,则需要取消离散点.判断边与障碍相交需要O(n),建图用时O(n^4).

最后运行Dijkstra算法即可,复杂度为O((V+E)logV)=O(n^3logn).

ProblemE:

Exchange

[Description]

卖订单SellOrder含:

供应物品个数,价格.

买订单BuyOrder含:

需物品个数,出价.

要求写一个交易系统.对于当前买订单,若当前价格最低的卖订单低于当前出价,则发生交易.对于当前卖订单,若当前出价最高的买订单,高于当前价格,则发生交易.当出价或价格相同时,按订单的先后循序发生交易.发生交易时,按供需物品个数的最小值交易.交易后,需要修改订单的供需物品个数.订单可以取消.

共3种命令:

买订单BUY,卖订单SELL,取消订单CANCEL.共n个命令.

每个命令后,输出当前处于最低价格的物品总数和当前处于最高出价的物品总数.

(n<=10000)

[Solution]

每次要取最小或最大,所以订单队列是一个优先队列.用最大堆模拟买订单,用最小堆模拟卖订单.直接模拟.总复杂度为O(nlogn).

ProblemF:

Fool'sGame

[Description]

[Solution]

ProblemG:

Graveyard

[Description]

长度为10000的圆上,等距分布着n个点.现在再加入m个点.要使得n+m个点在圆在等距分布.这就可能需要移动原来的n个点到新位置上,要求移动(沿着圆周移动)的总距离和最小.(n,m<=1000)

[Solution]

可以转化为在单位圆上每个正n边形A的顶点到内接正n+m边形B的最近顶点的距离和最短.问题就在于得出,A,B之间的角位置关系.(图左)

可以证明,存在一个最优解,A和B的顶点至少有一个顶点重合.对于任意一个顶点不重合的方案,找出A中离B最近顶点的距离最短的顶点P,P离B的顶点Q最近.从P向Q微移一个无限小量.不少于一半的A的点都向自己的B的最近顶点前进了一个无限小量.

所以令A,B其中一个点重合,很容易就算出答案了.总复杂度O(n).

ProblemH:

HardLife

[Description]

给出无向图G(V,E),求一个子图G'(V',E'),使得比值|E'|/|V'|最大.(|V|<=100,|E|<=1000)

[Solution]

本题可以描述为:

其中Xv,Ye的取值为0或1,表示点或边是否选取.这是一个0-1分数规划(0-1fractionalprogramming).可以通过如下参数搜索的方法解决.关于答案

构造一个新问题

:

设原问题的最优解是

显然有

.设两个变量

<

.由于

>=0,把

的最优解向量

代入

中,必会得到一个更大的z值,所以z单调递减.所以有:

这就意味着可以进行二分搜索答案

.注意初始范围:

.关于01分数规划参见[1]或最优比率生成树的解法.

这样将问题转化为求

的最大值.它需要满足限制:

边(u,v)的选取,需要点u,v的选取.这样的依赖关系与函数的形式使我们想到了最小割来解决这类问题,参见[2].建立二分图,X部的点Xv代表点v,Y部的点Ye代表边e.若边e关联了2个点u,v,则分别从Xu,Xv向Ye连一条容量为正无限的边.再建立源S,汇T.由S向每个Xv连容量为λ的边,由每个Ye向T连容量为1的边.这样求出该网络的最小割Mincut.则

.

求最小割的过程使用最大流的EdmondsKarp算法.点数为O(|V|+|E|),边数为O(|E|).每次找增广轨需O(|E|).共增广O(|E|^2)次.算法总复杂度为O(|E|^3logR).而实际情况会比这个估计好很多.稀疏二分图的增广次数达不到O(|E|^2).这题使用Relabeltofront的PreflowPush算法O(|E|^3),反而会超时.

另一解:

直接保留原图,即若原图存在边(u,v),从Xu到Xv连一条容量为正无限的边,同时从Xv到Xu也连一条容量为正无限的边.再建立源S,汇T.由S向每个Xv连容量为m的边,由每个Xv向T连容量为m-Dv+2λ的边.其中Dv表示点v的度.若此网络的最小割,即为z.由于点数为O(|V|),边数为O(|E|).使用PreflowPush的复杂度为O(|V|^3),效果很好.

[Reference]

[1]T.Matsui,Y.Saruwatari,MaikoShigeno,AnAnalysisofDinkelbach'sAlgorithmfor0-1FractionalProgrammingProblems(1992)

[2]TheIntroductiontoAlgorithm,Problems26-3:

Spaceshuttleexperiments.

ProblemI:

Interconnect

[Description]

给出无向图G(V,E).每次操作任意加一条非自环的边(u,v),每条边的选择是等概率的.问使得G连通的期望操作次数.(|V|<=30,|E|<=1000)

[Solution]

图的状态的表示:

由于每次加边是等概率的,且只需要考虑图的连通性,每次加边要么不改变连通性,要么把两个连通块合并.只要把图的连通状况表示出来.于是,状态就是每个连通块的大小的集合.即

.其中Ci为每个连通块,共k个连通块.这样的状态有多少个呢?

实际上就是对应n的整数拆分的个数.f(n,k)表示把n拆分为k份的个数,有:

由上式得到:

f(30,30)=5604.状态数不多.

记当前状态为

由于点的标号是没有关系的,为避免状态重复,规定

.设

表示状态S到完全连通的期望步数.即边界

.有如下方程成立:

其中

表示连通块Ci,Cj合并后的状态.

表示使连通块Ci,Cj合并的可能加边的个数.

表示总可能加边数.其中

表示使状态S不改变的可能加边的个数.该方程等式右边有两个部分:

每次加边要么不改变连通性,要么把两个连通块合并.S与S'是满足拓补序的,即g(S')不会依赖g(S).这样就可以动态规划.最后关于g(S)解一元一次方程即可.实现上,可以采用记忆化搜索,使用Hash表存状态.复杂度为O(f(n,n)*n^2).

ProblemJ:

JavavsC++

[Description]

Java风格的变量:

单词之间无分隔符;除了首单词全小写外,所有单词的首字母大写,其他字母小写.如:

javaIdentifier,longAndMnemonicIdentifier,name,nEERC.

C++风格的变量:

单词之间以下划线"_"分隔;所有字母小写.cidentifier,longandmnemonicidentifier,name,n_e_e_r_c.

要求对于给出的变量风格相互转化,或报错.

[Solution]

若即含下划线又含大写字母或非法字符,报错.

若以下划线"_"开头或结尾,或出现连续的下划线"__",报错.

经过以上判断后,一定是合法的.

含下划线的,就是C++风格.否则就是Java风格.模拟即可.

ProblemK:

Kickdown

[Description]

给出2个长度不超过100且列高度只为1或2的段.需要将它们放入一个高度为3的容器,问能够容纳它们的最短容器长度.如将左图的两个段,镶嵌后,放入右图的容器中.

[Solution]

枚举两个段的相对位置,可以固定一个段,枚举另一个段关于固定段的偏移量.确定位置后,用O(n)时间检查两个段是否可以镶嵌在一个高度为3的容器中.最后取合法方案中最短长度的一个.总复杂度为O(n^2).

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 小学教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1