《ACM算法与程序设计》解题报告模板
ACM 2011部分题目解题报告
![ACM 2011部分题目解题报告](https://img.taocdn.com/s3/m/116db0116edb6f1aff001f67.png)
更新: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解题报告
![ACM解题报告](https://img.taocdn.com/s3/m/9b6f85e0998fcc22bcd10d52.png)
问题重述:给出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解题报告
![ACM解题报告](https://img.taocdn.com/s3/m/d85d2322ee06eff9aef807b5.png)
题目一: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解题模版 密码破译
![ACM解题模版 密码破译](https://img.taocdn.com/s3/m/9a5d8361f5335a8102d2207c.png)
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算法模板(吉林大学)
![ACM算法模板(吉林大学)](https://img.taocdn.com/s3/m/8755c745b307e87101f69670.png)
目录目录 (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 算法的一种队列实现,减少了不必要的冗余计算。
算法分析与程序设计——报告模板
![算法分析与程序设计——报告模板](https://img.taocdn.com/s3/m/66065d6927d3240c8447ef85.png)
报告范例 动态规划法解0-1
2011级2班
作者姓名
背包问题是一个经典问题……这部分描述问题,并给出分析过程用来引出下面的算
法。
二、算法设计(或算法步骤)
用动态规划法解0-1背包问题……这部分详细描述解题算法思想或者具体算法步骤。
三、算法实现
此部分要有完整的程序源代码和运行结果截图。
还要有适当的说明,比如数据结构的选择和存储、变量的作用等,源代码中要有适当的注释。
四、算法分析(与改进)
此部分要有两方面的分析,以时间复杂度为主,有分析过程和结果。
如果有改进算法的想法,可以加在这部分,给出改进算法的清晰描述。
第三个报告中,此部分还要有几种解题方法的比较。
报告成绩单。
ACM课件!!月赛解题报告
![ACM课件!!月赛解题报告](https://img.taocdn.com/s3/m/32f6f7eb19e8b8f67c1cb975.png)
�
月赛解题报告(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 stemps 1.3.1解题报告](https://img.taocdn.com/s3/m/c3eb05785acfa1c7aa00cca8.png)
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道题中,基本全是涉及到贪心算法的题。
ACM I Love this Game 解题报告
![ACM I Love this Game 解题报告](https://img.taocdn.com/s3/m/db967951c381e53a580216fc700abb68a882ad45.png)
解题报告:Phone numbers题目来源:解法或类型: 动态规划作者:张志强A traditional game is played between two players on a pool of n numbers (not necessarily distinguishing ones).The first player will choose from the pool a number x1 lying in [a, b] (0 < a < b), which means a <= x1 <= b. Next the second player should choose a number y1 such that y1 - x1 lies in [a, b] (Attention! This implies y1 > x1 since a > 0). Then the first player should choose a number x2 such that x2 - y1 lies in [a, b]... The game endswhen one of them cannot make a choice. Note that a player MUST NOT skip his turn.A player's score is determined by the numbers he has chose, by the way:player1score = x1 + x2 + ...player2score = y1 + y2 + ...If you are player1, what is the maximum score difference (player1score - player2score) you can get? It is assumed that player2 plays perfectly.解题思路:01,,n x x -是可以选择的数,注意到两个选手选出来的数都是递增的,所以我们现将X 从小到大排序。
ACM新生赛题目解题报告2
![ACM新生赛题目解题报告2](https://img.taocdn.com/s3/m/acdaa502f12d2af90242e634.png)
Hosted by 计算机与信息科学系解题报告2012.5.1912:00~17:00本题册总共有10道题目,页数共有39页。
注意事项1、比赛网址是:。
2、可以带一切纸质材料,严禁携带U盘等电子类产品。
3、杜绝网上搜索资料和互相抄袭,如有发现,上报学校处分。
4、本测试系统采用的是window平台的服务器,int类型为4个字节,__int64为8个字节,8个字节的输出格式为printf(“%I64d\n”,n);5、有问题可以举手找志愿者。
6、比赛结束将分发答案参考程序。
1、Be Good at GuassingTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Problem DescriptionGive you many positive integer N (N<=23),for each N, just output N*(N+1)/2 integers in a single line, separated by space. (Don't ask me why.)For each N, the output line contains integers from 1 to N, and each just once. Again, do not ask me why, thank you. I'm so busy. But I can tell you a secret, the output has relationship with number triangle. As:(N=3)12 63 4 5See the sample for more information.InputMany lines, each line contains a positive integer N (N<=23).3426Sample Output1 2 6 3 4 51 2 9 3 10 8 4 5 6 71 2 31 2 15 3 16 14 4 17 21 13 5 18 19 20 12 6 7 8 9 10 11 解题代码#include<iostream>using namespace std;#include<fstream>#include<cstring>#include<cstdlib>#include<ctime>const int maxN = 24;int tri[maxN][maxN];int main(){int N,value,row,col,dir,i,j;while(cin>>N){memset(tri,0,sizeof(tri));row=col=1;for(value=1;value<=N;++value)tri[row++][col]=value;row=N,col=2;for(value=N+1;value<=2*N-1;++value) tri[row][col++]=value;row=N-1,col=N-1;for(value=2*N;value<=3*N-3;++value) tri[row--][col--]=value;row=2,col=2;value=3*N-2;dir=1;while(value<=N*(N+1)/2){if(1==dir)/*down one line*/{if((0==tri[row+1][col]))tri[++row][col]=value;else{dir=2;tri[row][++col]=value;}}else if(2==dir)/*right one line*/ {if((0==tri[row][col+1]))tri[row][++col]=value;else{dir=3;tri[--row][--col]=value;}}else{if((0==tri[row-1][col-1]))tri[--row][--col]=value;else{dir=1;tri[++row][col]=value;}}++value;}for(row=1;row<=N;++row){for(col=1;col<=row;++col){cout<<tri[row][col];if(!(row==N&&col==row))cout<<" ";}}cout<<endl;}return 0;}2、工院宅男Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Problem Description男女比例严重失调的工院向来不乏宅男,Jim做为茫茫一员,每天过着三点一线的生活,宿舍、饭店、教室。
20112011年ACM-ICPC协会程序设计大赛解题报告
![20112011年ACM-ICPC协会程序设计大赛解题报告](https://img.taocdn.com/s3/m/9d1cf91e6bd97f192279e91e.png)
Problem2 : 畅通工程
Output
对每个测试用例,在1行里输出最少还需要建设的道路数目。
Problem2 : 畅通工程
Sample Input
42 13 43 33 12 13 23 52 12 35 999 0 0
Sample Output
1 0 2 998
Problem2 : 畅通工程
Preparation Knowledge
表示集合的三种方式(数据结构): • 数组, • 树, • 图。
Problem2 : 畅通工程
Preparation Knowledge
A
B
C
D
E
F
Problem2 : 畅通工程
Solution
1. 2. 假设每个城市都是不相交的;(每个元素都是树根) 随着道路的连接,将连通的城市合并到同一个集合; (集合中的元素拥有同样的树根) 3. 统计出一共有多少个集合,输出结果。
Problem2 : 畅通工程
Examples
1 2 3 4 5
Problem2 : 畅通工程
Examples
1 2 3 4 5
1
1
3
4
5
1
1
3
4
3
Problem1 : ZOJ
Input
题目包含多组用例,每组用例占一行,包含ZOJ三个字符,当输入“E”时表示输入结束。 1<=length<=100。
Output
对于每组输入,请输出一行,表示按照要求处理后的字符串。 具体可见样例。
Problem1 : ZOJ
Sample Input
ZZOOOJJJ ZZZZOOOOOJJJ ZOOOJJ E
UESTC-第五届ACM趣味程序设计竞赛第四场(正式赛)--不完全解题报告
![UESTC-第五届ACM趣味程序设计竞赛第四场(正式赛)--不完全解题报告](https://img.taocdn.com/s3/m/6f14e8f5760bf78a6529647d27284b73f242366e.png)
UESTC-第五届ACM趣味程序设计竞赛第四场(正式赛)--不完全解题报告⽐赛链接:A. ---UESTC 1913简单博弈,先假设在警察先⾛的情况下分析,⼩偷先⾛的结果在其基础上取反⾯即可。
我是这样做的,随便假设⼩偷在⼀个点,在这个点的四周都是必败态(警察抓不到),然后⼀步可以到达必败态的点都是必胜态,⼀次推向远处,容易发现规律:当abs(xp-xt)%2==abs(yp-yt)%2时都是必败态,否则是必败态,这是结果已经得出。
两个特殊情况: 1.开始时两⼈在同⼀点,算YES。
2.格⼦为n*1或1*m形式,必然可以抓到,算YES。
代码:#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <string>#include <vector>#include <map>#include <set>#include <time.h>#include <queue>#include <cctype>#include <numeric>#include <cstdlib>#include <iomanip>#include <sstream>#define mod 1000000007#define INT 2147483647#define pi acos(-1.0)#define eps 1e-3#define lll __int64#define ll long longusing namespace std;#define N 200005int main(){int t,i;int n,m;int xp,yp,xt,yt;int flag;char ss[10];scanf("%d",&t);while(t--){flag = 1;scanf("%d%d",&n,&m);scanf("%d%d%d%d",&xp,&yp,&xt,&yt);scanf("%s",ss);if((n == 1 || m == 1)||(xp == xt && yp == yt)){cout<<"YES\n";continue;}int ka = abs(yp-yt);int kb = abs(xp-xt);if(ka%2 == kb%2){flag = 0;}if(ss[0] == 'p'){if(flag)cout<<"YES"<<endl;elsecout<<"NO"<<endl;}else{if(flag)cout<<"NO"<<endl;elsecout<<"YES"<<endl;}}return0;}View CodeB. ---UESTC 1916我的思路如下:从第⼀个字符串(后⽂称a)中第⼀个字符扫起,遇见⼀个字母(如'A'),如果没有标记,则标记为第⼆个字符串(后⽂称b)的该位字母,然后在循环⾥⾯扫⼀遍a,如果有等于这个字母的,⽽b对应的不相等,或者,不等于这个字母⽽b对应的⼜相等了,则tag = 0,说明不是,否则就是。
ACM图论解题报告
![ACM图论解题报告](https://img.taocdn.com/s3/m/9887d504ba0d4a7303763a5e.png)
ACM图论解题报告图论1 题意:输入cas n m 输入n个数输入m组每组表示一个范围内l r 中小于num 的数的个数注意从l是0开始的思路:区间内找数很容易联想到划分树划分树是用来求一个区间内的第k 大的数那我们可以找出第1第2第3.。
大数的值和num进行比较用二分法很容易找到第几大的数小于且等于num_include_lt;stdio.h_gt;_include_lt;algorithm_gt;using namespace std;_define M 100005int tree[40][M],sorted[M];int toLeft[40][M];void build(int level,int left,int right){if(left==right)return ;int mid=(left+right)_gt;_gt;1;int i;int suppose;//假设在中位数sorted[mid]左边的数都全部小于sorted[mid] suppose=mid-left+1;for(i=left;i_lt;=right;i++){if(tree[level][i]_lt;sorted[mid]){suppose--;}}//如果suppose==1,则说明数组中值为sorted[mid]只有一个数。
比如序列:1 3 4 5 6,sorted[mid]=4/_如果suppose_gt;1,则说明数组中左半边值为sorted[mid]的不止一个数,为mid-suppose。
比如序列:1 4 4 4 6,sorted[mid]=4_/int lpos=left,rpos=mid+1;for(i=left;i_lt;=right;i++){if(i==left){//这里是预处理,相当与初始化toLeft[level][i]=0;}else{toLeft[level][i]=toLeft[level][i-1];}if(tree[level][i]_lt;sorted[mid]){//划分到中位数左边 toLeft[level][i]++;tree[level+1][lpos++]=tree[level][i];。
ACM第一期训练题解题报告
![ACM第一期训练题解题报告](https://img.taocdn.com/s3/m/7424da71a26925c52cc5bfa2.png)
第一期训练题解题报告(1013、1016、1017)曾志平解题报告,就是将自己AC了的题的算法用文字/公式描述出来,并附上代码。
养成撰写解题报告的习惯,有利于加深自己对所用算法的理解和记忆,并且可以帮助后来者更快的学习ACM。
以下是第一期训练题中的思考题的解题报告。
HDU1013解题报告:题意理解:将一个正整数的各数位上数字相加,直到和为个位数为止。
注意,题目没有指定正整数的取值范围,所以可能会很大,位数可达500.算法思路:1.用char number[N]字符数据保存整数,N取个足够大的值,比如500;2.将字符串数组按元素进行求和,ASCII码的计算公式为ans +=number[i] – 48;3.如果计算出来的ans大于10,则将ans转换为字符串,转到第二步;4.否则,输出ans。
代码:int main(){char a[1000];int i, ans;while(scanf("%s", a) && a[0]!='0'){i=ans=0;while(1){while(a[i]!='\0')ans += a[i++] - 48;if(ans>9){sprintf(a, "%d", ans);i = ans = 0;}else break;}printf("%d\n", ans);}return 0;}HDU1016解题报告:题意理解:给你一个有n个节点的圆环,将数字1~n分别填入n 个节点中,要求任意两个相邻节点中的数字的和为素数。
题目指定了n的范围为0<n<20;算法思路:使用回溯法的最基本形式1.将1放入第一个节点(题目要求),进入下一个节点;2.递归:按顺序将2~n中的可用数字m放入当前节点(用for循环),如m加前一个节点中的数字为素数,则进入下一个节点,递归重复本步;若所有可用数字和前一个节点中的数字的和都不为素数,则返回递归的上一层;3.若当前节点是最后一个节点,且最后剩下的数字m和前一个节点中的数字的和,以及m+1都为素数,则从1开始依次输出各节点中的数字;否则,返回上一层递归,回到步骤2;4.直到所有的可能性都测试过了,算法终止。
FAFU第一次ACM月赛解题报告
![FAFU第一次ACM月赛解题报告](https://img.taocdn.com/s3/m/b57fd35d804d2b160b4ec05f.png)
FAFU第一次ACM月赛解题报告赛前预计:参赛人数60,人均通过题数2.8题左右,较不易3道通过人次为3-4次。
第一名A7题。
赛后结果参赛人数52,人均通过题数 2.33题。
较不易通过4人次。
第一名A 6题5题3人。
总提交数461,每题都至少有1人通过,基本符合比赛目标。
Problem A:讨厌的数学复杂度:O(1)难度:★本题练手题。
Problem B:帮冬儿忙复杂度:O(log(n) )难度:★★★★整除K就得整除K中的每个素数分子,这样就先把K化成素数相乘,然后对每一个素数进行判断C(n,m)中所含的个数,取最小值,便是结果。
但是,如何解决C(n,m)含有一素数的个数呢。
可以把C(n,m)化成 n!/(m!*(n-m)!) 从而转成n!中含有一素数的个数,这可以用O(log(n))解决,所以问题圆满解决。
本题代码较少,思路没什么陷阱和绕弯,但要求对素数比较深刻的理解,此题定为中下难度题。
Problem C:王子与公主复杂度:O(n*m*log(n*m) )难度:★★★本题求的是点和点之间的最短路径,主要考察的是广度优先搜索和优先队列的结合使用。
本题用到的数据结构如下:struct node{int x,y,t,key;bool operator <( const node &b){//(重载运算符’<’,指示优先队列按t的大小把最小的排在队头)return t>b.t;}};广度优先用到的数据结构,其中x,y代表王子此时所在的位置,t是到达此位置所用的时间,key代表王子从原始位置到当前位置所得到的食物,用二进制表示,即如果(key&(1<<i))==1表示王子当前拥有第i中食物。
刚开始时:x=0,y=0,t=0,key=0(没有任何食物)。
然后将刚开始时的状态加入优先队列中。
广度优先时从队列头取出时间最小的状态进行扩展,扩展时是向4个方向进行,当扩展到的位置有魔兽时,如果此时手上有它喜欢的食物,就直接贿赂它,否则就打败它;还有一点是要判断当前位置有无食物,如果有食物就要取走食物,具体操作是:tmp.key=(cur.key|(1<<当前含有食物的种类))。
2008年浙江省赛ACM解题报告
![2008年浙江省赛ACM解题报告](https://img.taocdn.com/s3/m/b8b9ce6daf1ffc4ffe47ac8d.png)
2008年5月17日,在浙江大学成功举行了浙江省第五届大学生程序设计竞赛。
本人的解题报告如下:A 简单题因为p的范围很小才99 所以从700-799就可以满足全部要求了。
可以打表出来,找出每个连续的一段满足要求的数,保存起来(并且要求新存的段长度比原先的要长),打出一张表,对每个要求的数,2分答案。
(把1-99的结果都保存好,直接输出)。
反正“转折点”很少,怎么搞都可以。
B 简单题直接bfs无向图mst。
C 中等偏难。
给定直线,对每条直线,传说解不等式组可以过,直接看是否存在一个点在直线之上。
(左端点取max,右端点取min,如果左>=右,直接break掉)。
有点ft...O(n^2) n=5000 rp好的可以过....我用的方法类似于凸包,先把所有直线按照斜率a由小到大排序,斜率相同取b较大的,扔掉b小的。
于是所有直线斜率不同。
准备一个栈,栈里面存放上一次能看到的“最上面”的直线以及这条直线能看到的范围x(x值右边的部分可以被看到)。
初始时,把斜率最小的直线入栈,并记录x值为-inf。
然后对第i条直线,所做的是用第i条直线和栈顶直线求交点x,如果这个x值不大于栈顶的x值,则把栈顶元素弹出,继续求交,否则退出。
这种判断操作直到栈为空,或者当前栈顶的x值大于栈顶的x值。
然后把第i条直线入栈,继续,看后面的直线。
最后栈中的直线数就是能看到的。
这种做法类似于凸包的方法,除去排序外,每条直线至多出入栈一次,复杂度O(n)。
总复杂度是O(nlogn)。
D 难题。
这题是比较有意思和有搞头的题。
应该可以算压轴题吧。
题目意思不难,但是很难做。
我想了好久,想出个方法,但是比vb的方法难一些。
其实可以贪心。
首先集合大小为1时,没法搞,直接判断掉。
我们把A集合和B集合里的数都由小到大排序。
要移动元素并且保证代价,那么可以选择的操作方法是A和B交换一些元素,然后A再给B(或者B再给A)若干个元素。
我们只讨论最后A再给B若干个数的情形,B给A的可以类似讨论。
2009 ACM world final 解题报告
![2009 ACM world final 解题报告](https://img.taocdn.com/s3/m/d43108d049649b6648d747b1.png)
I'll try to post some analysis here.Problem A.First, we loop over 8! possible orderings for the landing of the planes. Then, we do binary search on the answer. Having fixed the answer, we simply land each plane in the chosen order at the earliest possible time.Problem B.This problem requires careful checking of all boundary cases, and doesn't seem to require any particular insight. One just verifies the output of the original scheme on all given inputs, as well as the output of all "wrong" schemes that can be obtained from the given one by introducing one mistake (since there's not more than 19 gates, there's not more than 57 such schemes), and then checks if the output can be uniquely determined. But there surely is some trickiness to implementing that.Problem C.This is a very well-known problem if the ant moves along the surface of the cube; the octahedron doesn't change much. We try all possible ways to lay out the octahedron's sides on the plane (first place the first side, then place any of its neighbors next to it, and so on). The number of possible layouts should be on the order of hundreds or thousands. And in at least one layout, the shortest path will be just a straight segment - so we need to check those segments in all layouts, throw away those that go outside the layout, and then find the shortest one of the remaining. This solution should work as long as no shortest path passes through the same side twice; I don't have a proof for that, but intuitively it seems true. The implementation w ill require a LOT of accuracy, though.Problem D.One thing that comes to mind is to draw all possible layouts on paper, and figure out the formulas for the answer in each of them. But that's veryerror-prone, so I hope there's a more concise solution.Problem E.Take any vertex in the graph. Let's say it has a "nice left" if any path from the start to that vertex has the same cost. Let's say is has a "nice right" if any path from the end to that vertex has the same cost.This can be determined by DFSen.If there's a vertex without both nice left and nice right, then there's no solution: at least one of the roads to the right of it will have to be modified, and at least one of the roads to the left of it will have to be modified - so there will be a path with two modified roads.Otherwise, the vertices split into 3 sets: A - vertices with nice left but no nice right, B - vertices with nice left and nice right, and C - vertices with nice right but no nice left. If both A and C are empty, the constraints are already satisfied and there's no need to change anything. Othewise, A will always have the start vertex, C will always have the end vertex.Let's assume for now that B is empty. The above argument about no path with two modified roads tells us that the only way to achieve what's required is to modify the roads that lead from A to C. More specifically: take all pairs of vertices a from A and c from C, where there exists and edge from a to c. The cost of that edge plus the cost of the path from start to a and from c to end is a lower bound for the answer. Take the highest of those lower bounds, say H, and change the cost of each edge between a from A and c from C toH-cost(start,a)-cost(c,end). This will quite obviously be the minimal possible answer, and every path will have the same cost of H since it will pass along exactly one edge from A to C.Now, how to deal with B? It turns out that we can simply put all vertices from B to C, and the above solution will still work - since it always leaves at least one route from start to end unchanged, it can't make a non-optimal answer; and it will always produce a correct answer since the only thing it requires is for all vertices from A have a "nice left" and all vertices from C have a "nice right".Does that make sense? :)Problem F.First, let's learn how to calculate the length of one fence required to enclose the given set of points. To find that fence, we find the convex hull of that set of points, and then "extend" it to the outside by the given margin. The result may have a complex structure of straight and circular segments, but its total length is easily computed: the total length of straight segments is equal to the perimeter of the convex hull, and the total length of circular segments is equal to one circle, 2*pi*margin (because you have to "rotate" by 2*pi to complete the cycle - when you're moving in straight line, your direction doesn't change). The rest of the problem is standard: we do a DP that calculates the minimum possible cost for each subset of points, by choosing a subset of that subset to be contained by one fence, and taking the previously-computed DP value for the rest of the points.Problem G.I think this problem requires one just to implement the game's rules carefully. The number of possible states in the game is reasonably small: the position is characterized by the number of cards still lying in the row, the cards held by both players, if any, and the layout of the "top line" of the house of cards - which will always include not more than 8 cards. This gives us a rough estimate of C(26,10)*26 states, which is roughly 100 million - but in realitymuch less of the states will be reachable, since the top line only contains 8 cards in one case, and so on.Problem H.If we introduce variables x1,x2,... for the decisions on the bills, then satisfying all ministers can be formulated via statements of form "if x5 is false, then x7 is true" (since if at least one decision contradicts minister's choices, then all his other choices must be respected). That gives us an instance of 2-CNF satisfiability problem, and its solution is well-known. Checking which variables have the same value in any solution is also quite routinely added to that well-known solution (for example, we fix that variable and run the satisfiability checking again).Problem I.Another implementation problem here. One should understand the problem statement, and then simulate all resizes going from the outermost window inside.Problem J.We can try solving this with a binary search + DP. We binary search over the answer, then do a DP on subtrees. For each subtree, consider all possible roundings that don't contradict the chosen answer (that is, the paths completely inside the subtree don't change by more than that answer), and from each of those roundings, we're interested in the lowest and highest differences for paths from the root of that subtree to its vertices (these two values are the only ones that affect paths that pass through the root of that subtree). So the DP can be: for a subtree T and a lower bound L on the difference on the paths from its root, what is the lowest possible upper bound U on that difference? This should give us only at most of 100*30*100 states, and I think the processing of all states can be done in at m ost 100*30*100 time (since there're only 100 edges, and "updating" along each edge will take one scan along a 30*100 array that has the U's for each L), thus even a binary search outside still leaves the running time reasonable.I know this is very unclear, but I think the only way to figure out the details is to actually start coding the solution, and I'm too lazy for that :)A shot at clarifying: for a subtree, there're 3 parameters:1) the maixmum modulus of delta for paths inside that subtree2) the maximum delta for paths from the root of that subtree into the subtree3) the minimum delta for paths from the root of that subtree into the subtree Without the binary search, we'd be forced to add the 1st parameter to the DP, and that would make it too slow. That's why we use binary search outside. Problem K.Consider the chain of transformation in the optimal answer. Consider the change(s) that affect the leftmost character of the string. Between those changes, the transformation is split into independent parts. That gives us the possibility of the following DP: consider the set of all suffixes of length L of all given strings (S,T, and all transformation strings). There're at most 202 of those for each L. Now, let's calculate the best way to transform each of those strings to each other, given that we know such answers for smaller values of L. First, we account for the transformations that don't involve the whole L characters - we can just take the value from the L-1 step. And then, there are transformations with the whole L characters - they are given by rules of length exactly L. And then, we need to combine those two kinds with a shortest-paths algorithm, like the Floyd-Warshall. That gives us 202^3 running time for each L, so about 160 million very simple operation for each testcase - that should be enough.So that makes about 170 minutes for all solutions with some interruptions :) It's nice that they don't have problems that are theoretically impossible to solve during the contest.。
浙江师范大学第10届ACM竞赛解题报告
![浙江师范大学第10届ACM竞赛解题报告](https://img.taocdn.com/s3/m/de9629ebf8c75fbfc77db295.png)
第十届“北大青鸟”杯浙江师范大学程序设计竞赛解题报告(罗方炜,lfw2565295@ ,浙师大10计软)比赛概述首先是本届比赛的题目:总共11题本次比赛的提交统计:其中A,C,K相对简单,B,D,F为中等题,E,G,H为稍难题,I,J没人解出本次比赛前十名的情况:有两名同学成功解出8道,还有1名同学解出7道,6道的有些数量,同时恭喜前6名获得本次比赛的一等奖,同时前十名获得比赛奖品——T恤。
题目讲解A:Yes Or NoTime Limit: 1000MS Memory Limit: 65536KTotal Submissions: 596 Accepted: 94Description在二维平面上有两点P1(x1,y1),P2(x2,y2),现今,P1想向P2靠拢,但只能往斜上方走(x1+1,y1+1),或往斜下方走(x1+1,y1-1)。
请问P1能否抵达P2,如果可以输出Yes,否则输出No。
Input第一行为一个正整数t(t<=100),代表测试组数。
每一组测试数据:一行有四个整数x1,y1,x2,y2。
(各数值均大于等于0且小于等于100000)Output对于每一组测试数据,输出一行结果:如果P1能够抵达P2,输出Yes否则,输出NoSample Input30 0 1 10 0 2 00 0 3 0Sample OutputYesYesNoHint没忘记初中方程组就秒了这题拿下Second Blood吧~思路:此题被作为简单题,意思是从一个点A要走到另外一个点B是否可行,而行走的办法只能是两种,即从(x,y)点出发,下一步只能到(x+1,y+1)(*)或者(x+1,y-1)(**),这可以设一个方程,设(*)走了a次,(**)走了b次,那么联立以后就是x1+a+b=x2;y1+a-b=y2;那么方程就是求是否有a>=0和b>=0满足这个方程组,很多同学卡在这题是因为根本没有想到这个方法。
- 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);}。