POJ 1009不算解题报告的解题报告

2024-03-29 08:38
文章标签 报告 poj 解题 不算 1009

本文主要是介绍POJ 1009不算解题报告的解题报告,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

    好久没有写poj的题了,一定要坚持下来。毕竟是要写写代码为生的,算法的重要性不言而喻。1009这道题已经纠结了很久了,其实题目不难,看到后思路也很直观,就是考虑到同一个数字跨过三行以上时,中间部分肯定就可以不用计算,直接为零。之前觉得可以建立一个map,当包括中间值在内的9个数组成的数组之前已经算过的话,直接输出map的value就可以了。不过似乎这样每次搜寻、比较,效率反而低了。另外,写的时候想着如果输入的数据比较多,它们的个数之和可能会超过int范围,看来是我多想了。

    这道题总算硬着头皮“看”完了。自己尝试了几遍都没有完成,最后还是看了大牛的解题报告。所以其实自己也没有写完。在这里总结一下,希望有提高。

    写程序的时候按照框架写,先想好要分几部分,然后再扩充每部分的细节内容。这道不难的题,我一开始就被细节部分弄的一点信心也没有了。

    这是大牛的代码。这里加了一点注释。源代码可以参见http://xay0.blog.163.com/blog/static/43925338200801202220646/

   c++ code:

thestoryofsnow1009Accepted228K16MSC++4691B
#include <stdio.h>
#include <assert.h>int n, t, k;
int num[2000], sum[2000], digit[2000], ansdigit[5000], ansnum[5000];
//求绝对值函数,可以用math中的同名函数
int abs(int x)
{if (x < 0) return -x;return x;
}
//循环变量i和周围元素位置映射
/*****
*0 1 2
*3   4
*5 6 7
******/
inline int map(int c, int now)
{switch (c){case 0: return now - t - 1;case 1: return now - t;case 2: return now - t + 1;case 3: return now - 1;case 4: return now + 1;case 5: return now + t - 1;case 6: return now + t;case 7: return now + t + 1;}assert(false);return -1;
}
//算出位置y的元素值,这里forward很巧妙,为0向前找,为1向后找
int number(int c, int y, bool forward)
{int i;if (forward){for (i = c; i <= n; ++i)if (sum[i] >= y) break;return i;}else{for (i = c; i > 0; --i)if (sum[i] < y) break;return i+1;}
}
//判断边界情况 
bool ok(int now, int i)
{if (now < t && (i == 1 || i == 0 || i == 2)) return false;//起始行的前一行if (now > sum[n] - t && (i == 6 || i == 5 || i == 7)) return false;//结束行的后一行if (now % t == 1 && (i == 0 || i == 3 || i == 5)) return false;//左边一行的左边if (now % t == 0 && (i == 2 || i == 4 || i == 7)) return false;//右边一行的右边return true;
}
//比较与周围8个元素之差的绝对值大小
int get(int x, int now)
{int i, max = 0, m;for (i = 0; i < 8; ++i){m = map(i, now);if (ok(now, i) && m > 0 && m <= sum[n]){m = number(x, m, i / 4);if (max < abs(digit[x] - digit[m])) max = abs(digit[x] - digit[m]);}}return max;
}
//减少重复计算 
int late(int x, int now, int r)
{int p;if (r <= now) return 1;if (now % t != 1){if (digit[number(x, now - 1, 0)] != digit[x]) return 1;if (now > t){p = number(x, now - t - 1, 0);if ((sum[p] - 1) / t < (now - 1) / t){if (sum[p] <= now - t + 1) return 1;if (r > sum[p] - 1 + t) r = sum[p] - 1 + t;}}if (now <= sum[n] - t){p = number(x, now + t - 1, 1);if ((sum[p] - 1) / t == (now - 1) / t + 1){if (sum[p] <= now + t + 1) return 1;if (r > sum[p] - 1 - t) r = sum[p] - 1 - t;}}return r - now + 1;}else{if (now > t){p = number(x, now - t, 0);if ((sum[p] - 1) / t < (now - 1) / t){if (sum[p] <= now - t + 1) return 1;if (r > sum[p] - 1 + t) r = sum[p] - 1 + t;}}if (now <= sum[n] - t){p = number(x, now + t, 1);if ((sum[p] - 1) / t == (now - 1) / t + 1){if (sum[p] <= now + t + 1) return 1;if (r > sum[p] - 1 - t) r = sum[p] - 1 - t;}}return r - now + 1;}
}
//程序的主体部分,计算start和end之间的部分。这段程序实际上是个递归,多行的情况可以归约到start和end在同一行的情况
void make(int x, int start, int end)
{int i, r;int a = (start - 1) / t, b = (end - 1) / t;if (a != b)//如果不在同一行{make(x, start, b * t);//归约make(x, b * t + 1, end);//同一行的情况return;}//通过get函数算出最大的绝对值,保存在last中,the保存当前位置算出的最大绝对值。如果两者相同,就要进行合并int last = get(x, start), sum = 0, the;for (i = start; i <= end;){the = get(x, i);r = late(x, i, end - 1);if (the == last)sum += r;//合并else{ansdigit[++k] = last;ansnum[k] = sum;sum = r;last = the;}i += r;}ansdigit[++k] = last;ansnum[k] = sum;
}
int main()
{int i, x, y;sum[0] = 0;while (scanf("%d", &t) && t){i = 0;k = 0;while (scanf("%d%d", &x, &y) && (x || y)){digit[++i] = x; //digit数组保存输入元素num[i] = y;//num数组保存元素个数sum[i] = sum[i - 1] + num[i];//sum数组记录元素个数和,主要用于判断元素i的周围8个元素是什么}n = i;for (i = 1; i <= n; ++i){if (num[i] <= t + t + 2)//不存在同一个元素跨越3行的情况make(i, sum[i - 1] + 1, sum[i]);else{make(i, sum[i - 1] + 1, sum[i - 1] + t + 1);//前面部分同if部分ansdigit[++k] = 0;//中间直接为0ansnum[k] = num[i] - 2 * t - 2;//0的个数make(i, sum[i] - t, sum[i]);//后面部分也需要计算}}printf("%d\n", t);//输出开始for (i = 1; i <= k;){int outdigit = ansdigit[i];int outnum = 0;while (i <= k && ansdigit[i] == outdigit)//如果相邻元素相同,需要合并outnum += ansnum[i++];printf("%d %d\n", outdigit, outnum);}printf("0 0\n");}printf("0\n");
}


这篇关于POJ 1009不算解题报告的解题报告的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

【专题】2024飞行汽车技术全景报告合集PDF分享(附原数据表)

原文链接: https://tecdat.cn/?p=37628 6月16日,小鹏汇天旅航者X2在北京大兴国际机场临空经济区完成首飞,这也是小鹏汇天的产品在京津冀地区进行的首次飞行。小鹏汇天方面还表示,公司准备量产,并计划今年四季度开启预售小鹏汇天分体式飞行汽车,探索分体式飞行汽车城际通勤。阅读原文,获取专题报告合集全文,解锁文末271份飞行汽车相关行业研究报告。 据悉,业内人士对飞行汽车行业

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

poj 1511 Invitation Cards(spfa最短路)

题意是给你点与点之间的距离,求来回到点1的最短路中的边权和。 因为边很大,不能用原来的dijkstra什么的,所以用spfa来做。并且注意要用long long int 来存储。 稍微改了一下学长的模板。 stack stl 实现代码: #include<stdio.h>#include<stack>using namespace std;const int M

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

poj 1287 Networking(prim or kruscal最小生成树)

题意给你点与点间距离,求最小生成树。 注意点是,两点之间可能有不同的路,输入的时候选择最小的,和之前有道最短路WA的题目类似。 prim代码: #include<stdio.h>const int MaxN = 51;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int P;int prim(){bool vis[MaxN];

poj 2349 Arctic Network uva 10369(prim or kruscal最小生成树)

题目很麻烦,因为不熟悉最小生成树的算法调试了好久。 感觉网上的题目解释都没说得很清楚,不适合新手。自己写一个。 题意:给你点的坐标,然后两点间可以有两种方式来通信:第一种是卫星通信,第二种是无线电通信。 卫星通信:任何两个有卫星频道的点间都可以直接建立连接,与点间的距离无关; 无线电通信:两个点之间的距离不能超过D,无线电收发器的功率越大,D越大,越昂贵。 计算无线电收发器D

poj 1502 MPI Maelstrom(单源最短路dijkstra)

题目真是长得头疼,好多生词,给跪。 没啥好说的,英语大水逼。 借助字典尝试翻译了一下,水逼直译求不喷 Description: BIT他们的超级计算机最近交货了。(定语秀了一堆词汇那就省略吧再见) Valentine McKee的研究顾问Jack Swigert,要她来测试一下这个系统。 Valentine告诉Swigert:“因为阿波罗是一个分布式共享内存的机器,所以它的内存访问

uva 10061 How many zero's and how many digits ?(不同进制阶乘末尾几个0)+poj 1401

题意是求在base进制下的 n!的结果有几位数,末尾有几个0。 想起刚开始的时候做的一道10进制下的n阶乘末尾有几个零,以及之前有做过的一道n阶乘的位数。 当时都是在10进制下的。 10进制下的做法是: 1. n阶位数:直接 lg(n!)就是得数的位数。 2. n阶末尾0的个数:由于2 * 5 将会在得数中以0的形式存在,所以计算2或者计算5,由于因子中出现5必然出现2,所以直接一