《ACM算法与程序设计》解题报告模板
ACM 2011部分题目解题报告

更新:G题在UVA上面随便交了个O(n^3logC)的居然就这么过了...Problem A题意就是找一个最优的操作序列使得p经过序列处理>=r且q经过处理<=s对于m=1的情况可以特殊处理m>=2的时候,显然M的个数不可能太多,于是枚举M的个数,假设操作序列中有n个M 假设序列中第i个M后面紧跟了Ai个A(Ai>=0),那么对某个数x的处理结果就是((((x+A0*a)*m+A1)*m+A2)...+An-1)*m+An=x*m^n+a*(A0*m^n+A1*m^(n-1)+...+An)因此p*m^n+a*(A0*m^n+A1*m^(n-1)+...+An)>=r且q*m^n+a*(A0*m^n+A1*m^(n-1)+...+An)<=s稍作处理可得(r-p*m^n)/a=r'<=A0*m^n+A1*m^(n-1)+...+An<=s'=...然后显然对于i>=1,Ai>=m显然不是最优的,因此对于i>=1有0<=Ai<m这可以认为是一个m进制数(除了最高位),找出范围内的最小数Amin和最大数Amax那么从Amin的最高位(也就是A0)开始从高位到低位,每一位要么取值当前的Ai,要么Ai+1(如果没有超过Amax)且后面的低位都为0,如此找到一个数位和最小的数,这个数就对应了最优的那个操作序列Problem B显然先平移还是先拉伸是没有关系的枚举旋转角度且将坐标舍入,然后枚举对应关系,然后解方程组寻找是否存在合法的平移+拉伸的变换矩阵Problem CFloodFill找连通块,每个黑色的连通块对应一个字符,然后根据黑色连通块内部的白色的“洞”的数量判断是哪个字符Problem D不会做...Problem E首先坐标系旋转45度那么当距离为d的时候,每个咖啡店的覆盖范围就是以该咖啡店为中心边长为d*sqrt(2)的且边平行于坐标轴的正方形那么判断一个点被多少个咖啡店覆盖只要看以该点为中心边长为d*sqrt(2)的正方形内有多少个咖啡店预处理从左上角到每个坐标内的正方形内的咖啡店数量,每个询问只需对每个坐标的查询一下即可Problem F一个暴力的DP方程是f(i)=max{Gi*(Dj-Di-1)+f(j)}+Ri-Pi这可以归结到一个更一般的f(i)=max(Ki*Xj+f(j))+Ci把所有的(Xj,f(j))画在平面上,用一条斜率为-Ki的直线从下向上扫,那么最上面的那个点就是最优的因此可以把所有的(Xj,f(j))和(X(j+1),f(j+1))用线段连起来,然后如果有下凹的点那么这个点对于任何斜率一定都不可能最优因此可以直接删去,于是得到了一段上凸的东西于是解DP方程可以直接按照斜率二分,总的复杂度是O(NlgN)Problem G给定一堆线段,围成的多边形面积最大要求所有点位于同一个外接圆上,圆的半径可以二分搞定就是不知道O(n^3)的能不能过Problem H求割点,然后对剩下的点做floodfill找出一坨坨非割点连通块显然如果割点存在的话必然存在至少一个非割点连通块仅与一个割点相连,那么这样的连通块里面需要放一个逃生通道然后割点显然不需要逃生通道,与两个或以上割点相连的连通块也不需要于是就出解了Problem I二分答案,假设当前要判断是否能够在t时间内不被吃掉那么以自己为中心的边长为2t的正方形就是自己的活动范围,以每个木乃伊为中心的边长为2t的正方形就是木乃伊的活动范围,只要自己的正方形没有被木乃伊们完全覆盖那么就意味着可以不被吃把所有的木乃伊按照x坐标排序,然后用个线段树记录当前被木乃伊覆盖了的y坐标,沿x 轴扫一遍就可以了复杂度O(二分答案*NlgN)Problem J首先预处理,令f(n)表示n个方块至少要分解为金字塔的个数然后根据f(n)可以优化所有的f(n+m)的值,其中m为任意一个的金字塔的体积并且n+m<=10^6同时如果发现f(n)+1=f(n+m)是最优的并且m是f(n+m)分解出的金字塔里面最大的那么就记录g(n+m)=m,如此记录方案预处理复杂度O(c^(4/3))对于输入的每一个c,沿着g(c)一路找下去就可以了Problem K旋转卡壳,用两条平行的卡壳来找最短距离总体评价:CJK算最简单的题目,B我觉得很简单但是不知道为什么很少人做...A和H稍微难一些点,E不难就是写起来有点小复杂G不知道O(n^3)的算法能不能过,不过应该会去写写试试F就是个斜率优化,应该是很经典的DP模型,不过由于我和YY的DP功力都比较水因此想了一个多小时才想到求上凸线...不知道换了LMY上场情况如何了I想到二分答案后面的就简单了...MB我又犯了上次GCJ一样的错误跑去想构造...不过看这题的状况我怀疑全场都去想构造去了...?D属于神题,完全没有任何思路...总的来说,感觉今年的题目比去年容易很多,可参考HJ在这篇日志中的吐槽换我们去年Final队的配置前4小时ABCEHJK这7题只要不卡题不脑残应该没什么压力。
ACM解题报告

问题重述:给出n种邮票,每种邮票有自己的面值(面值可能重复)指定m种“总面值”,对每种“总面值”,求解满足如下条件的组合以达到该“总面值”(1)所用邮票在n种中可以重复选取(2)所用邮票张数〈=4(3)尽量多的适应那个不同总类的邮票Max (Stamp Types)(4)若有多种方案满足(3),则选取张数最小的一种方案Min (Stamp Num)(5)若有多种方案满足(3)(4),则选取“最大面额”最高的一种方案。
Max(Heightest Value) (6)若有多种方案满足(3)(4)(5)则输出“tie”题目分析:(1)算法定位:从题目的条件可知,此题必须遍求所有方案以求解,因此采用搜索的方法是非常合理的,因为题目带由一定的递推性,也可以尝试动态规划的方法.(2)问题优化与简化对于搜索型题目,关键的优化就是减少重复计算,本题可由3方面的简化,避免重复性计算.(1)对于面额相等的邮票,可以限制在1~5张,多余的可以不处理,例如这样的输入:1 1 1 1 1 1 1 1 0 8个14 0可以简化成为:1 1 1 1 1 0 5个14 0他们的解是相同的(2)搜索求解时约定, 后一张邮票面额>=前面张邮票的面额,即如下的6种情况:1 2 3 2 3 1 3 12 1 3 2 3 2 1 2 1 3只需搜索判断一种,即 1 2 3 的情况(3)对于给定的n种邮票,遍历4张邮票的所有可达“总面额”的解,当m种指定面额给出,只需插标输出即可,不需要重复m次类似的搜索。
(因为m次的搜索中,很多是重复计算的)(3)算法介绍(1)搜索方法一:(base on 史诗’s program)主要思路:4重循环,枚举所有可能,依据题目条件保留最优解。
For(i=1;i<=total_stamps;i++)For(j=i;j<=total_stamps;j++)For(k=j;k<=total_stamps;k++)For(l=k;l<=total_stamps;l++){更新最优解}优化:使用优化方案(1)(2),修改后可以加上优化方案(3)评价:编程复杂度低,代码少,运行时空效率高,比赛时候推荐使用但是扩展性受限制,若题目给的是任一k张而不是4,则必须大量修改代码(2)搜索方法二:(base on hawking’s program)主要思路:递归深度搜索,遍历所有k张邮票的可达面额的解,保留每种面额的最优解,查表输出指定面额的解,并给定k=4,即为题目要求的情况。
ACM解题报告

题目一:DescriptionSome positive integers can be represented by a sum of one or more consecutive prime numbers. How many such representations does a given positive integer have? For example, the integer 53 has two representations 5 + 7 + 11 + 13 + 17 and 53. The integer 41 has three representations 2+3+5+7+11+13, 11+13+17, and 41. The integer 3 has only one representation, which is 3. The integer 20 has no such representations. Note that summands must be consecutive primenumbers, so neither 7 + 13 nor 3 + 5 + 5 + 7 is a valid representation for the integer 20.Your mission is to write a program that reports the number of representations for the given positive integer.InputThe input is a sequence of positive integers each in a separate line. The integers are between 2 and 10 000, inclusive. The end of the input is indicated by a zero. OutputThe output should be composed of lines each corresponding to an input line except the last zero. An output line includes the number of representations for the input integer as the sum of one or more consecutive prime numbers. No other characters should be inserted in the output.Sample Input231741206661253Sample Output1123121.算法通过筛法找出10000以内所有的素数,存到数组里。
ACM解题模版 密码破译

Each charactor are changed to a corresponding charactor. If the keyword is "Angel", the rule will be:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
ANGELZYXWVUTSRQPOMKJIHFDCB
难点在于密码破译字母表的制作算法思想?数据结构?数组题目代码?includestdiohincludestringhcharch27bch27sch27
解题队伍:
JSU_10
题目类型:
解密
题目来源:
/1591
题目编号:
1591
题目描述:
Encoded Love-letter
temp[h]=1;
}
for(i=25,j=0;i>=len;i--,j++)
{
while(temp[j]==1)
j++;
Bch[i]=j+65;
}
for(i=0;i<26;i++)
Sch[i]=Bch[i]+32;
while(gets(ch1))
{
i=0;
while(ch1[i]!='\0')
ACM算法模板(吉林大学)

目录目录 (1)Graph 图论 (3)|DAG的深度优先搜索标记 (3)|无向图找桥 (3)|无向图连通度(割) (3)|最大团问题DP+DFS (3)|欧拉路径O(E) (3)|D IJKSTRA数组实现O(N^2) (3)|D IJKSTRA O(E* LOG E) (4)|B ELLMAN F ORD单源最短路O(VE) (4)|SPFA(S HORTEST P ATH F ASTER A LGORITHM) (4)|第K短路(D IJKSTRA) (5)|第K短路(A*) (5)|P RIM求MST (6)|次小生成树O(V^2) (6)|最小生成森林问题(K颗树)O(MLOGM) (6)|有向图最小树形图 (6)|M INIMAL S TEINER T REE (6)|T ARJAN强连通分量 (7)|弦图判断 (7)|弦图的PERFECT ELIMINATION点排列 (7)|稳定婚姻问题O(N^2) (7)|拓扑排序 (8)|无向图连通分支(DFS/BFS邻接阵) (8)|有向图强连通分支(DFS/BFS邻接阵)O(N^2) (8)|有向图最小点基(邻接阵)O(N^2) (9)|F LOYD求最小环 (9)|2-SAT问题 (9)Network 网络流 (11)|二分图匹配(匈牙利算法DFS实现) (11)|二分图匹配(匈牙利算法BFS实现) (11)|二分图匹配(H OPCROFT-C ARP的算法) (11)|二分图最佳匹配(KUHN MUNKRAS算法O(M*M*N))..11 |无向图最小割O(N^3) (12)|有上下界的最小(最大)流 (12)|D INIC最大流O(V^2*E) (12)|HLPP最大流O(V^3) (13)|最小费用流O(V*E* F).......................................13|最小费用流O(V^2* F). (14)|最佳边割集 (15)|最佳点割集 (15)|最小边割集 (15)|最小点割集(点连通度) (16)|最小路径覆盖O(N^3) (16)|最小点集覆盖 (16)Structure 数据结构 (17)|求某天是星期几 (17)|左偏树合并复杂度O(LOG N) (17)|树状数组 (17)|二维树状数组 (17)|T RIE树(K叉) (17)|T RIE树(左儿子又兄弟) (18)|后缀数组O(N* LOG N) (18)|后缀数组O(N) (18)|RMQ离线算法O(N*LOG N)+O(1) (19)|RMQ(R ANGE M INIMUM/M AXIMUM Q UERY)-ST算法(O(NLOGN +Q)) (19)|RMQ离线算法O(N*LOG N)+O(1)求解LCA (19)|LCA离线算法O(E)+O(1) (20)|带权值的并查集 (20)|快速排序 (20)|2台机器工作调度 (20)|比较高效的大数 (20)|普通的大数运算 (21)|最长公共递增子序列O(N^2) (22)|0-1分数规划 (22)|最长有序子序列(递增/递减/非递增/非递减) (22)|最长公共子序列 (23)|最少找硬币问题(贪心策略-深搜实现) (23)|棋盘分割 (23)|汉诺塔 (23)|STL中的PRIORITY_QUEUE (24)|堆栈 (24)|区间最大频率 (24)|取第K个元素 (25)|归并排序求逆序数 (25)|逆序数推排列数 (25)|二分查找 (25)|二分查找(大于等于V的第一个值) (25)|所有数位相加 (25)Number 数论 (26)|递推求欧拉函数PHI(I) (26)|单独求欧拉函数PHI(X) (26)|GCD最大公约数 (26)|快速GCD (26)|扩展GCD (26)|模线性方程 A * X = B (% N) (26)|模线性方程组 (26)|筛素数[1..N] (26)|高效求小范围素数[1..N] (26)|随机素数测试(伪素数原理) (26)|组合数学相关 (26)|P OLYA计数 (27)|组合数C(N, R) (27)|最大1矩阵 (27)|约瑟夫环问题(数学方法) (27)|约瑟夫环问题(数组模拟) (27)|取石子游戏1 (27)|集合划分问题 (27)|大数平方根(字符串数组表示) (28)|大数取模的二进制方法 (28)|线性方程组A[][]X[]=B[] (28)|追赶法解周期性方程 (28)|阶乘最后非零位,复杂度O(NLOGN) (29)递归方法求解排列组合问题 (30)|类循环排列 (30)|全排列 (30)|不重复排列 (30)|全组合 (31)|不重复组合 (31)|应用 (31)模式串匹配问题总结 (32)|字符串H ASH (32)|KMP匹配算法O(M+N) (32)|K ARP-R ABIN字符串匹配 (32)|基于K ARP-R ABIN的字符块匹配 (32)|函数名: STRSTR (32)|BM算法的改进的算法S UNDAY A LGORITHM (32)|最短公共祖先(两个长字符串) (33)|最短公共祖先(多个短字符串)...............................33Geometry 计算几何.. (34)|G RAHAM求凸包O(N* LOG N) (34)|判断线段相交 (34)|求多边形重心 (34)|三角形几个重要的点 (34)|平面最近点对O(N* LOG N) (34)|L IUCTIC的计算几何库 (35)|求平面上两点之间的距离 (35)|(P1-P0)*(P2-P0)的叉积 (35)|确定两条线段是否相交 (35)|判断点P是否在线段L上 (35)|判断两个点是否相等 (35)|线段相交判断函数 (35)|判断点Q是否在多边形内 (35)|计算多边形的面积 (35)|解二次方程A X^2+B X+C=0 (36)|计算直线的一般式A X+B Y+C=0 (36)|点到直线距离 (36)|直线与圆的交点,已知直线与圆相交 (36)|点是否在射线的正向 (36)|射线与圆的第一个交点 (36)|求点P1关于直线LN的对称点P2 (36)|两直线夹角(弧度) (36)ACM/ICPC竞赛之STL (37)ACM/ICPC竞赛之STL简介 (37)ACM/ICPC竞赛之STL--PAIR (37)ACM/ICPC竞赛之STL--VECTOR (37)ACM/ICPC竞赛之STL--ITERATOR简介 (38)ACM/ICPC竞赛之STL--STRING (38)ACM/ICPC竞赛之STL--STACK/QUEUE (38)ACM/ICPC竞赛之STL--MAP (40)ACM/ICPC竞赛之STL--ALGORITHM (40)STL IN ACM (41)头文件 (42)线段树 (43)求矩形并的面积(线段树+离散化+扫描线) (43)求矩形并的周长(线段树+离散化+扫描线) (44)Graph 图论/*==================================================*\| DAG的深度优先搜索标记| INIT: edge[][]邻接矩阵; pre[], post[], tag全置0;| CALL: dfstag(i, n); pre/post:开始/结束时间\*==================================================*/int edge[V][V], pre[V], post[V], tag;void dfstag(int cur, int n){ // vertex: 0 ~ n-1pre[cur] = ++tag;for (int i=0; i<n; ++i) if (edge[cur][i]) {if (0 == pre[i]) {printf("Tree Edge!\n");dfstag(i,n);} else {if (0 == post[i]) printf("Back Edge!\n");else if (pre[i] > pre[cur])printf("Down Edge!\n");else printf("Cross Edge!\n");}}post[cur] = ++tag;}/*==================================================*\| 无向图找桥| INIT: edge[][]邻接矩阵;vis[],pre[],anc[],bridge 置0;| CALL: dfs(0, -1, 1, n);\*==================================================*/int bridge, edge[V][V], anc[V], pre[V], vis[V];void dfs(int cur, int father, int dep, int n){ // vertex: 0 ~ n-1if (bridge) return;vis[cur] = 1; pre[cur] = anc[cur] = dep;for (int i=0; i<n; ++i) if (edge[cur][i]) {if (i != father && 1 == vis[i]) {if (pre[i] < anc[cur])anc[cur] = pre[i];//back edge}if (0 == vis[i]) { //tree edgedfs(i,cur,dep+1,n);if (bridge) return;if (anc[i] < anc[cur]) anc[cur] = anc[i];if (anc[i] > pre[cur]) { bridge = 1; return; } }}vis[cur] = 2;}/*==================================================*\| 无向图连通度(割)| INIT: edge[][]邻接矩阵;vis[],pre[],anc[],deg[]置为0;| CALL: dfs(0, -1, 1, n);| k=deg[0], deg[i]+1(i=1…n-1)为删除该节点后得到的连通图个数| 注意:0作为根比较特殊!\*==================================================*/int edge[V][V], anc[V], pre[V], vis[V], deg[V];void dfs(int cur, int father, int dep, int n){// vertex: 0 ~ n-1int cnt = 0;vis[cur] = 1; pre[cur] = anc[cur] = dep;for (int i=0; i<n; ++i) if (edge[cur][i]) {if (i != father && 1 == vis[i]) {if (pre[i] < anc[cur])anc[cur] = pre[i];//back edge}if (0 == vis[i]) { //tree edgedfs(i,cur,dep+1,n);++cnt; // 分支个数if (anc[i] < anc[cur]) anc[cur] = anc[i];if ((cur==0 && cnt>1) ||(cnt!=0 && anc[i]>=pre[cur]))++deg[cur];// link degree of a vertex }}vis[cur] = 2;} /*==================================================*\| 最大团问题 DP + DFS| INIT: g[][]邻接矩阵;| CALL: res = clique(n);\*==================================================*/int g[V][V], dp[V], stk[V][V], mx;int dfs(int n, int ns, int dep){if (0 == ns) {if (dep > mx) mx = dep;return 1;}int i, j, k, p, cnt;for (i = 0; i < ns; i++) {k = stk[dep][i]; cnt = 0;if (dep + n - k <= mx) return 0;if (dep + dp[k] <= mx) return 0;for (j = i + 1; j < ns; j++) {p=stk[dep][j];if (g[k][p]) stk[dep + 1][cnt++] = p;}dfs(n, cnt, dep + 1);}return 1;}int clique(int n){int i, j, ns;for (mx = 0, i = n - 1; i >= 0; i--) {// vertex: 0 ~ n-1for (ns = 0, j = i + 1; j < n; j++)if (g[i][j]) stk[1][ ns++ ] = j;dfs(n, ns, 1); dp[i] = mx;}return mx;}/*==================================================*\| 欧拉路径O(E)| INIT: adj[][]置为图的邻接表; cnt[a]为a点的邻接点个数;| CALL: elpath(0); 注意:不要有自向边\*==================================================*/int adj[V][V], idx[V][V], cnt[V], stk[V], top;int path(int v){for (int w ; cnt[v] > 0; v = w) {stk[ top++ ] = v;w = adj[v][ --cnt[v] ];adj[w][ idx[w][v] ] = adj[w][ --cnt[w] ];// 处理的是无向图—-边是双向的,删除v->w后,还要处理删除w->v}return v;}void elpath (int b, int n){ // begin from b int i, j;for (i = 0; i < n; ++i) // vertex: 0 ~ n-1 for (j = 0; j < cnt[i]; ++j)idx[i][ adj[i][j] ] = j;printf("%d", b);for (top = 0; path(b) == b && top != 0; ) {b = stk[ --top ];printf("-%d", b);}printf("\n");}/*==================================================*\| Dijkstra数组实现O(N^2)| Dijkstra --- 数组实现(在此基础上可直接改为STL的Queue实现)| lowcost[] --- beg到其他点的最近距离| path[] -- beg为根展开的树,记录父亲结点\*==================================================*/#define INF 0x03F3F3F3Fconst int N;int path[N], vis[N];void Dijkstra(int cost[][N], int lowcost[N], int n, int beg){ int i, j, min;memset(vis, 0, sizeof(vis));vis[beg] = 1;for (i=0; i<n; i++){lowcost[i] = cost[beg][i]; path[i] = beg;}lowcost[beg] = 0;path[beg] = -1; // 树根的标记int pre = beg;for (i=1; i<n; i++){min = INF;dist[v] = dist[u] + c;for (j=0; j<n; j++)// 下面的加法可能导致溢出,INF 不能取太大if (vis[j]==0 &&lowcost[pre]+cost[pre][j]<lowcost[j]){lowcost[j] =lowcost[pre] + cost[pre][j]; path[j] = pre; } for (j=0; j<n; j++) if (vis[j] == 0 && lowcost[j] < min){ min = lowcost[j]; pre = j; } vis[pre] = 1; } } /*==================================================*\ | Dijkstra O(E * log E) | INIT: 调用init(nv, ne)读入边并初始化; | CALL: dijkstra(n, src); dist[i]为src 到i 的最短距离 \*==================================================*/ #define typec int // type of cost const typec inf = 0x3f3f3f3f; // max of cost typec cost[E], dist[V]; int e, pnt[E], nxt[E], head[V], prev[V], vis[V]; struct qnode { int v; typec c; qnode (int vv = 0, typec cc = 0) : v(vv), c(cc) {} bool operator < (const qnode& r) const { return c>r.c; } }; void dijkstra(int n, const int src){ qnode mv; int i, j, k, pre; priority_queue<qnode> que; vis[src] = 1; dist[src] = 0; que.push(qnode(src, 0)); for (pre = src, i=1; i<n; i++) { for (j = head[pre]; j != -1; j = nxt[j]) { k = pnt[j]; if (vis[k] == 0 && dist[pre] + cost[j] < dist[k]){ dist[k] =dist[pre] + cost[j]; que.push(qnode(pnt[j], dist[k])); prev[k] = pre; } } while (!que.empty() && vis[que.top().v] == 1) que.pop(); if (que.empty()) break ; mv = que.top(); que.pop(); vis[pre = mv.v] = 1; } } inline void addedge(int u, int v, typec c){ pnt[e] = v; cost[e] = c; nxt[e] = head[u]; head[u] = e++; } void init(int nv, int ne){ int i, u, v; typec c; e = 0;memset(head, -1, sizeof (head));memset(vis, 0, sizeof (vis));memset(prev, -1, sizeof (prev));for (i = 0; i < nv; i++) dist[i] = inf;for (i = 0; i < ne; ++i) {scanf("%d%d%d", &u, &v, &c);// %d: type of cost addedge(u, v, c); // vertex: 0 ~ n-1, 单向边 }}/*==================================================*\| BellmanFord 单源最短路O(VE)| 能在一般情况下,包括存在负权边的情况下,解决单源最短路径问题| INIT: edge[E][3]为边表| CALL: bellman(src);有负环返回0;dist[i]为src 到i 的最短距| 可以解决差分约束系统: 需要首先构造约束图,构造不等式时>=表示求最小值, 作为最长路,<=表示求最大值, 作为最短路 (v-u <= c:a[u][v] = c )\*==================================================*/#define typec int // type of costconst typec inf=0x3f3f3f3f; // max of costint n, m, pre[V], edge[E][3];typec dist[V];int relax (int u, int v, typec c){if (dist[v] > dist[u] + c) {pre[v] = u; return 1; } return 0; } int bellman (int src){ int i, j;for (i=0; i<n; ++i) { dist[i] = inf; pre[i] = -1; } dist[src] = 0; bool flag; for (i=1; i<n; ++i){ flag = false; // 优化 for (j=0; j<m; ++j) { if( 1 == relax(edge[j][0], edge[j][1], edge[j][2]) ) flag = true; } if( !flag ) break; } for (j=0; j<m; ++j) { if (1 == relax(edge[j][0], edge[j][1], edge[j][2])) return 0; // 有负圈 } return 1; } /*==================================================*\ | SPFA(Shortest Path Faster Algorithm) Bellman-Ford 算法的一种队列实现,减少了不必要的冗余计算。
算法分析与程序设计——报告模板

报告范例 动态规划法解0-1
2011级2班
作者姓名
背包问题是一个经典问题……这部分描述问题,并给出分析过程用来引出下面的算
法。
二、算法设计(或算法步骤)
用动态规划法解0-1背包问题……这部分详细描述解题算法思想或者具体算法步骤。
三、算法实现
此部分要有完整的程序源代码和运行结果截图。
还要有适当的说明,比如数据结构的选择和存储、变量的作用等,源代码中要有适当的注释。
四、算法分析(与改进)
此部分要有两方面的分析,以时间复杂度为主,有分析过程和结果。
如果有改进算法的想法,可以加在这部分,给出改进算法的清晰描述。
第三个报告中,此部分还要有几种解题方法的比较。
报告成绩单。
ACM课件!!月赛解题报告

�
月赛解题报告(2006'12)
1001 How many days?
模拟题,数据量比较少,直接模拟就可以 过
1002 Color the ball
直接模拟会超时. 初始化一个数组array[100002]={0}. 对于每2个输入的a b, 我们做标记 array[a]++,array[b+1]--. 最后从第一个球开始计算,就可以求出每个球被涂的次数. Int count = 0; for(i = 1;i <= n; i++) { count += array[i]; printf("%d ", count); //此时的count的值就是第I球被涂的次数. } 大家可以画几个简单的例子,这样会很直观.
பைடு நூலகம்
1006 DNA squence
广搜+HASH.令li表示每个序列的长度 (i=1,2…n)可用n个正整数si(0=<si<=li)表示 搜索中的一个状态,则最坏情况下总的状态 数为6^8.此题即求由初态{0,0,…,0}变化到 目态{l1,l2,…ln}的最小步数.
1007 The more,The better
动态规划. 由输入的数据我们知道所构成的是一棵多叉树,我们可以把 它转化为二叉树来做. 对于一个节点来说,把它的第一个孩子作为父节点的左子树, 其它孩子作为第一个孩子的右子树.这样就可以把一棵普 通树化为二叉树. A[x][y] : 表示节点x攻克y个城堡所得最多宝物. A[x][y] = max(A[x.l][k-1] + x.v + A[x.r][y-k])), k = 0,1..y; x.l : 节点x的左孩子, x.r: 节点x的右孩子, x.v: 节点x的宝物 数量.
ACM stemps 1.3.1解题报告

ACM Steps1.3.1解题报告#include<iostream>#include<cstdio>using namespace std;int main(){float m,j[1001],f[1001],sum,temp,temp1;int n,i,t,k;while(cin>>m>>n){if(n==-1&&m==-1) break;for(i=0;i<n;i++)cin>>j[i]>>f[i];for(t=0;t<n-1;t++){for(k=0;k<n-t-1;k++)if((j[k]/f[k])<(j[k+1]/f[k+1])){temp=j[k];j[k]=j[k+1];j[k+1]=temp;temp1=f[k];f[k]=f[k+1];f[k+1]=temp1;}}sum=0;for(i=0;i<n;i++){if(m>f[i]){sum=sum+j[i];m=m-f[i];}else{sum=sum+m/f[i]*j[i];m=0;}if(m==0)break;}printf("%.3f\n",sum);}return 0;}这是一个求最优解的问题,要用到贪心算法的思维。
我的思路是:首先把它给的几组数按照j[i]/f[i]进行由大到小排序,然后把老鼠有的猫粮与仓库需要的猫粮进行比较,如果老鼠有的粮食有余,那就直接拿到这个仓库的所有的三明治,再又把老鼠剩余的粮食与下一个仓库所需的粮食进行比较,如果老鼠有的粮食还是有余,又直接拿到这个仓库的所有的三明治。
如此比较下去,如果老鼠有的粮食比仓库所需的粮食少,就按照比例得到这个仓库的三明治。
最后输出老鼠得到的所有的三明治,就可以得到本题的结果。
只要思维清晰,这样的题很快就以AC。
在这一章节的8道题中,基本全是涉及到贪心算法的题。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
电子科技大学期末解题报告课程:《ACM算法与程序设计》学院:学号:姓名:报告成绩:教师签名:讨厌的青蛙1、链接地址/problem?id=28122、问题描述在韩国,有一种小的青蛙。
每到晚上,这种青蛙会跳越稻田,从而踩踏稻子。
农民在早上看到被踩踏的稻子,希望找到造成最大损害的那只青蛙经过的路径。
每只青蛙总是沿着一条直线跳越稻田,而且每次跳跃的距离都相同,如图1所示。
稻田里的稻子组成一个栅格,每棵稻子位于一个格点上,如图2所示。
而青蛙总是从稻田的一侧跳进稻田,然后沿着某条直线穿越稻田,从另一侧跳出去,如图3所示。
问题描述青蛙的每一跳都恰好踩在一棵水稻上,将这棵水稻拍倒。
可能会有多只青蛙从稻田穿越,有些水稻被多只青蛙踩踏,如图4所示。
当然,农民所见到的是图5中的情形,看不到图4中的直线。
根据图5,农民能够构造出青蛙穿越稻田时的行走路径,并且只关心那些在穿越稻田时至少踩踏了3 棵水稻的青蛙。
因此,每条青蛙行走路径上至少包括3 棵被踩踏的水稻。
而在一条青蛙行走路径的直线上,也可能会有些被踩踏的水稻不属于该行走路径。
在图5中,格点(2, 1)、(6, 1)上的水稻可能是同一只青蛙踩踏的,但这条线上只有两棵被踩踏的水稻,因此不能作为一条青蛙行走路径;格点(2, 3)、(3, 4)、(6, 6)在同一条直线上,但它们的间距不等,因此不能作为一条青蛙行走路径;格点(2, 1)、(2, 3)、(2, 5)、(2, 7)是一条青蛙行走路径,该路径不包括格点(2, 6)。
请你写一个程序,确定在所有的青蛙行路径中,踩踏水稻棵数最多的路径上有多少棵水稻被踩踏。
例如,图5的答案是7,因为第6 行上全部水稻恰好构成一条青蛙行走路径。
输入数据从标准输入设备上读入数据。
第一行上两个整数R、C,分别表示稻田中水稻的行数和列数,1≤R、C≤5000。
第二行是一个整数N,表示被踩踏的水稻数量,3≤N≤5000。
在剩下的N 行中,每行有两个整数,分别是一颗被踩踏水稻的行号(1~R)和列号(1~C),两个整数用一个空格隔开。
而且,每棵被踩踏水稻只被列出一次。
输出要求从标准输出设备上输出一个整数。
如果在稻田中存在青蛙行走路径,则输出包含最多水稻的青蛙行走路径中的水稻数量,否则输出0。
输入样例6 7142 16 64 22 52 62 73 46 16 22 36 36 46 56 7输出样例73、解题思路这个问题看起来很复杂,其实目的很简单:帮助农民找到为害最大的青蛙。
也就是要找到一条穿越稻田的青蛙路径,这个路径上被踩踏的水稻不少于其他任何青蛙路径上被踩踏的水稻数。
当然,整个稻田中也可能根本就不存在青蛙路径。
问题的关键是:找到穿越稻田的全部青蛙路径。
任何一条穿越稻田的青蛙路径L,至少包括3 棵被踩踏的水稻。
假设其中前两棵被踩踏的水稻分别是(X1,Y1)、(X2,Y2),那么:●令dx=X2-X1、dy=Y2-Y1;X0=X1-dx、Y0=Y1- dy;X3=X2 +dx、Y3=Y2 + dy●(X0,Y0)位于稻田之外,青蛙从该位置经一跳后进入稻田、踩踏位置(X1,Y1)上的水稻●Xi=X0 + i×dx、Yi=Y1 + i×dy(i>3),如果(Xi,Yi)位于稻田之内,则(Xi,Yi)上的水稻必被青蛙踩踏根据上述规则,只要知道一条青蛙路径上的前两棵被踩踏的水稻,就可以找到该路径上其他的水稻。
为了找到全部的青蛙路径,只要从被踩踏的水稻中,任取两棵水稻(X1,Y1)、(X2,Y2),判断(X1,Y1)、(X2,Y2)是否能够作为一条青蛙路径上最先被踩踏的两颗水稻。
4、解决方案这个问题的描述中,最基本的元素是被踩踏的水稻。
在程序中要选择一个合适的数据结构,来表达这个基本元素。
这个数据结构是否合适的标准是:在程序中要表达这个元素时,能否用一个单词或者短语,即用一个变量来表示。
s truct PLANT //描述一棵被踩踏的水稻{int x; //水稻的行号int y; //水稻的列号}这个问题的主要计算是:从被踩踏的水稻中选择两棵(X1,Y1)、(X2,Y2)。
判断它们是否能够作为一条青蛙路径上最先被踩踏的两颗水稻。
(X1,Y1)、(X2,Y2)唯一确定了蛙跳的方向和步长,从(X2,Y2)开始,沿着这个方向和步长在稻田内走。
每走一步,判断所到达位置上(X,Y)的水稻是否被踩踏,直到走出稻田为止。
如果在某一步上,(X,Y)没有被踩踏,则表明(X1,Y1)、(X2,Y2)是一条青蛙路径上最先被踩踏的两颗水稻的假设不成立。
这个判断的算法在问题求解过程中要反复使用,它的效率成为决定整个计算效率的关键。
●用一个PLANT 型的数组plants[5001]表示全部被踩踏的水稻●将plants 中的元素按照行/列序号的升序(或者降序)排列采用二分法查找plants 中是否有值为(X,Y)的元素:将(X,Y)与plants 中间的元素比较,(1)相等,表明找到了元素;(2)比plants 中间元素的小,继续在plants 的前半部寻找;(3)比plants 中间元素的大,继续在plants 的后半部寻找。
采用上述方法判断每走一步所到达位置上(X,Y)的水稻是否被踩踏,最多只要比较log2N,其中N 是稻田中被踩踏水稻的总量。
5、源代码#include <stdio.h>#include <stdlib.h>int r,c,n;struct PLANT{int x,y;};PLANT plants[5001];PLANT plant;int myCompare(const void *ele1,const void *ele2);int searchPath(PLANT secPlant, int dX, int dY);int main(void){int i,j,dX,dY,pX,pY,steps,max=2;scanf("%d%d",&r,&c);scanf("%d",&n);for(i=0;i<n;i++)scanf("%d %d",&plants[i].x,&plants[i].y);qsort(plants,n,sizeof(PLANT),myCompare);//先竖向排列,再横向排列for(i=0;i<n-2;i++)for(j=i+1;j<n-1;j++){dX=plants[j].x-plants[i].x;dY=plants[j].y-plants[i].y;pX=plants[i].x-dX;pY=plants[i].y-dY;if(pX<=r&&pX>=1&&pY<=c&&pY>=1)//说明plants[i]不是青蛙进入稻田的起始点continue;if(plants[i].x+max*dX>r)//说明在该路径上不会出现更多被踩踏的break;//注意随着j的变化,dX只会增大pY=plants[i].y+max*dY;if(pY>c||pY<1)//注意行进方向为[-pi/2,pi/2)continue; //随着j的变化,dY可能会减小//steps表示路径上踩踏的水稻数,如果不成为路径,则为0steps=searchPath(plants[j],dX,dY);if(steps>max)max=steps;}if(max==2) max=0;printf("%d\n",max);return (0);}int myCompare(const void *ele1,const void *ele2){PLANT *p1,*p2;p1=(PLANT*)ele1;p2=(PLANT*)ele2;if(p1->x==p2->x) //优先竖向比较return(p1->y-p2->y);return (p1->x-p2->x);}int searchPath(PLANT secPlant,int dX,int dY ){PLANT plant;int steps;plant.x=secPlant.x+dX;plant.y=secPlant.y+dY;steps=2;while(plant.x<=r&&plant.x>=1&&plant.y<=c&&plant.y>=1) //没有出界{if(!bsearch(&plant,plants,n,sizeof(PLANT),myCompare)) //不成为路径{steps=0;break;}plant.x+=dX;plant.y+=dY;steps++;}return (steps);}。