ACM动态规划问题简易模板(C++可编译)
acm 算法模板 适合初学者使用
三角形面积计算 (1)字典树模板 (2)求线段所在直线 (5)求外接圆 (5)求内接圆 (6)判断点是否在直线上 (8)简单多边形面积计算公式 (8)stein算法求最大共约数 (9)最长递增子序列模板——o(nlogn算法实现) (9)判断图中同一直线的点的最大数量 (10)公因数和公倍数 (12)已知先序中序求后序 (12)深度优先搜索模板 (13)匈牙利算法——二部图匹配BFS实现 (15)带输出路径的prime算法 (17)prime模板 (18)kruskal模板 (19)dijsktra (22)并查集模板 (23)高精度模板 (24)三角形面积计算//已知三条边和外接圆半径,公式为s = a*b*c/(4*R)double GetArea(double a, double b, double c, double R){return a*b*c/4/R;}//已知三条边和内接圆半径,公式为s = prdouble GetArea(double a, double b, double c, double r){return r*(a+b+c)/2;}//已知三角形三条边,求面积double GetArea(doule a, double b, double c){double p = (a+b+c)/2;return sqrt(p*(p-a)*(p-b)*(p-c));}//已知道三角形三个顶点的坐标struct Point{double x, y;Point(double a = 0, double b = 0){x = a; y = b;}};double GetArea(Point p1, Point p2, Point p3){double t =-p2.x*p1.y+p3.x*p1.y+p1.x*p2.y-p3.x*p2.y-p1.x*p3.y+p2.x*p3.y;if(t < 0) t = -t;return t/2;}字典树模板#include <stdio.h>#include <string.h>#include <memory.h>#define BASE_LETTER 'a'#define MAX_TREE 35000#define MAX_BRANCH 26struct{int next[MAX_BRANCH]; //记录分支的位置int c[MAX_BRANCH]; //查看分支的个数int flag; //是否存在以该结点为终止结点的东东,可以更改为任意的属性}trie[MAX_TREE];int now;void init(){now = 0;memset(&trie[now], 0, sizeof(trie[now]));now ++;}int add (){memset(&trie[now], 0, sizeof(trie[now]));return now++;}int insert( char *str){int pre = 0, addr;while( *str != 0 ){addr = *str - BASE_LETTER;if( !trie[pre].next[addr] )trie[pre].next[addr] = add();trie[pre].c[addr]++;pre = trie[pre].next[addr];str ++;}trie[pre].flag = 1;return pre;}int search( char *str ){int pre = 0, addr;while( *str != 0 ){addr = *str - BASE_LETTER;if ( !trie[pre].next[addr] )return 0;pre = trie[pre].next[addr];str ++;}if( !trie[pre].flag )return 0;return pre;}pku2001题,源代码:void check( char *str ){int pre = 0, addr;while(*str != 0){addr = *str - BASE_LETTER;if( trie[pre].c[addr] == 1) {printf("%c\n", *str);return;}printf("%c", *str);pre = trie[pre].next[addr];str ++;}printf("\n");}char input[1001][25];int main(){int i = 0,j;init();while(scanf("%s", input[i]) != EOF){getchar();insert(input[i]);i++;}for(j = 0; j < i; j ++){printf("%s ", input[j]);check(input[j]);}return 0;}求线段所在直线//*****************************线段所在的直线struct Line{double a, b, c;};struct Point{double x, y;}Line GetLine(Point p1, Point p2){//ax+by+c = 0返回直线的参数Line line;line.a = p2.y - p1.y;line.b = p1.x - p2.x;line.c = p2.x*p1.y - p1.x*p2.y;return line;}求外接圆//***************已知三角形三个顶点坐标,求外接圆的半径和坐标********************struct Point{double x, y;Point(double a = 0, double b = 0){x = a; y = b;}};struct TCircle{double r;Point p;}double distance(Point p1, Point p2){return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));}double GetArea(doule a, double b, double c){double p = (a+b+c)/2;return sqrt(p*(p-a)*(p-b)*(p-c));}TCircle GetTCircle(Point p1, Point p2, Point p3){double a, b, c;double xa,ya, xb, yb, xc, yc, c1, c2;TCircle tc;a = distance(p1, p2);b = distance(p2, p3);c = distance(p3, p1);//求半径tc.r = a*b*c/4/GetArea(a, b, c);//求坐标xa = p1.x; ya = p1.b;xb = p2.x; yb = p2.b;xc = p3.x; yc = p3.b;c1 = (xa*xa + ya*ya - xb*xb - yb*yb)/2;c2 = (xa*xa + ya*ya - xc*xc - yc*yc)/2;tc.p.x = (c1*(ya-yc) - c2*(ya-yb))/((xa-xb)*(ya-yc) - (xa-xc)*(ya-yb)); tc.p.y = (c1*(xa-xc) - c2*(xa-xb))/((ya-yb)*(xa-xc) - (ya-yc)*(xa-xb));return tc;}求内接圆struct Point{double x, y;Point(double a = 0, double b = 0){x = a; y = b;}};struct TCircle{double r;Point p;}double distance(Point p1, Point p2){return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));}double GetArea(doule a, double b, double c){double p = (a+b+c)/2;return sqrt(p*(p-a)*(p-b)*(p-c));}TCircle GetTCircle(Point p1, Point p2, Point p3){double a, b, c;double xa,ya, xb, yb, xc, yc, c1, c2, f1, f2;double A,B,C;TCircle tc;a = distance(p1, p2);b = distance(p3, p2);c = distance(p3, p1);//求半径tc.r = 2*GetArea(a, b, c)/(a+b+c);//求坐标A = acos((b*b+c*c-a*a)/(2*b*c));B = acos((a*a+c*c-b*b)/(2*a*c));C = acos((a*a+b*b-c*c)/(2*a*b));p = sin(A/2); p2 = sin(B/2); p3 = sin(C/2);xb = p1.x; yb = p1.b;xc = p2.x; yc = p2.b;xa = p3.x; ya = p3.b;f1 = ( (tc.r/p2)*(tc.r/p2) - (tc.r/p)*(tc.r/p) + xa*xa - xb*xb + ya*ya - yb*yb)/2;f2 = ( (tc.r/p3)*(tc.r/p3) - (tc.r/p)*(tc.r/p) + xa*xa - xc*xc + ya*ya - yc*yc)/2;tc.p.x = (f1*(ya-yc) - f2*(ya-yb))/((xa-xb)*(ya-yc)-(xa-xc)*(ya-yb)); tc.p.y = (f1*(xa-xc) - f2*(xa-xb))/((ya-yb)*(xa-xc)-(ya-yc)*(xa-xb));return tc;}判断点是否在直线上//**************判断点是否在直线上********************* //判断点p是否在直线[p1,p2]struct Point{double x,y;};bool isPointOnSegment(Point p1, Point p2, Point p0){//叉积是否为0,判断是否在同一直线上if((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y) != 0)return false;//判断是否在线段上if((p0.x > p1.x && p0.x > p2.x) || (p0.x < p1.x && p0.x < p2.x)) return false;if((p0.y > p1.y && p0.y > p1.y) || (p0.y < p1.y && p0.y < p2.y)) return false;return true;}简单多边形面积计算公式struct Point{double x, y;Point(double a = 0, double b = 0){x = a; y = b;}};Point pp[10];double GetArea(Point *pp, int n){//n为点的个数,pp中记录的是点的坐标int i = 1;double t = 0;for(; i <= n-1; i++)t += pp[i-1].x*pp[i].y - pp[i].x*pp[i-1].y;t += pp[n-1].x*pp[0].y - pp[0].x*pp[n-1].y;if(t < 0) t = -t;return t/2;}stein算法求最大共约数int gcd(int a,int b){if (a == 0) return b;if (b == 0) return a;if (a % 2 == 0 && b % 2 == 0) return 2 * gcd(a/2,b/2); else if (a % 2 == 0) return gcd(a/2,b);else if (b % 2 == 0) return gcd(a,b/2);else return gcd(abs(a-b),min(a,b));}最长递增子序列模板——o(nlogn算法实现)#include <stdio.h>#define MAX 40000int array[MAX], B[MAX];int main(){int count,i,n,left,mid,right,Blen=0,num;scanf("%d",&count); //case的个数while(count--){scanf("%d",&n); //每组成员的数量Blen = 0;for(i=1;i<=n;i++)scanf("%d",&array[i]); //读入每个成员for(i=1;i<=n;i++){num = array[i];left = 1;right = Blen;while(left<=right){mid = (left+right)/2;if(B[mid]<num)left = mid+1;elseright = mid-1;}B[left] = num;if(Blen<left)Blen++;}printf("%d\n",Blen);//输出结果}return 1;}判断图中同一直线的点的最大数量#include <iostream>#include <cstdio>#include <memory>using namespace std;#define MAX 1010 //最大点的个数struct point{int x,y;}num[MAX];int used[MAX][MAX*2]; //条件中点的左边不会大于1000,just equal MAX int countN[MAX][MAX*2];#define abs(a) (a>0?a:(-a))int GCD(int x, int y){int temp;if(x < y){temp = x; x = y; y = temp;}while(y != 0){temp = y;y = x % y;x = temp;}return x;}int main(){int n,i,j;int a,b,d,ans;while(scanf("%d", &n)==1){//initeans = 1;memset(used, 0, sizeof(used));memset(countN, 0, sizeof(countN));//readfor(i = 0; i < n; i++)scanf("%d%d", &num[i].x, &num[i].y);for(i = 0; i < n-1; i++){for(j = i+1; j < n; j++){b = num[j].y-num[i].y;a = num[j].x-num[i].x;if(a < 0) //这样可以让(2,3)(-2,-3)等价{a = -a; b = -b;}d = GCD(a,abs(b));a /= d;b /= d; b += 1000;//条件中点的左边不会大于1000if(used[a][b] != i+1){used[a][b] = i+1;countN[a][b] = 1;}else{countN[a][b]++;if(ans < countN[a][b])ans = countN[a][b];}}//for}//forprintf("%d\n", ans+1);}return 0;}公因数和公倍数int GCD(int x, int y){int temp;if(x < y){temp = x; x = y; y = temp;}while(y != 0){temp = y;y = x % y;x = temp;}return x;}int beishu(int x, int y){return x * y / GCD(x,y);}已知先序中序求后序#include <iostream>#include <string>using namespace std;string post;void fun(string pre, string mid){if(pre == "" || mid == "") return;int i = mid.find(pre[0]);fun(pre.substr(1,i), mid.substr(0,i));fun(pre.substr(i+1, (int)pre.length()-i-1), mid.substr(i+1, (int)mid.length()-i-1));post += pre[0];}int main(){string pre, mid;while(cin >> pre){cin >> mid;post.erase();fun(pre, mid);cout << post << endl;}return 0;}深度优先搜索模板int t; //t用来标识要搜索的元素int count; //count用来标识搜索元素的个数int data[m][n]; //data用来存储数据的数组//注意,数组默认是按照1……n存储,即没有第0行//下面是4个方向的搜索,void search(int x, int y){data[x][y] = *; //搜索过进行标记if(x-1 >= 1 && data[x-1][y] == t){count++;search(x-1,y);}if(x+1 <= n && data[x+1][y] == t){count++;search(x+1,y);}if(y-1 >= 1 && data[x][y-1] == t){count++;search(x,y-1);}if(y+1 <= n && data[x][y+1] == t){count++;search(x,y+1);}}//下面是8个方向的搜索void search(int x, int y){data[x][y] = *; //搜索过进行标记if(x-1 >= 1){if(data[x-1][y] == t){count++;search(x-1,y);}if(y-1 >= 1 && data[x-1][y-1] == t) {count++;search(x-1,y-1);}if(y+1 <= n && data[x-1][y+1] == t) {count++;search(x-1,y+1);}}if(x+1 <= n){if(data[x+1][y] == t){count++;search(x+1,y);}if(y-1 >= 1 && data[x+1][y-1] == t) {count++;search(x+1,y-1);}if(y+1 <= n && data[x+1][y+1] == t) {count++;search(x+1,y+1);}}if(y-1 >= 1 && data[x][y-1] == t){count++;search(x,y-1);}if(y+1 <= n && data[x][y+1] == t){count++;search(x,y+1);}}匈牙利算法——二部图匹配BFS实现//匈牙利算法实现#define MAX 310 //二部图一侧顶点的最大个数int n,m; //二分图的两个集合分别含有n和m个元素。
acm动态规划例题
acm动态规划例题Problem A:简单的图形覆盖Time Limit:1000MS Memory Limit:65536KTotal Submit:201 Accepted:104Description有一个2*n 的方格,要用若干个1*2的模块覆盖,模块可以横放,也可以竖放.问对于给定的n(n<=100),有多少种不同的覆盖方法.Input有多个测试用例,每个用例占一行,为一个正整数nOutput对于每个测试用例,输出一行相应的结果Sample Input9 11Sample Output55 144分析:f(n)=??>-+-==2)2()1(2211n n f n f n n #include int A[101]; int main() {int n,i;while(scanf("%d",&n)!=EOF) {A[0]=1;A[1]=2;if(n==1||n==0) printf("%d\n",A[0]);else if(n==2) printf("%d\n",A[1]);else{for(i=2;i<n;i++)< p="">A[i]=A[i-1]+A[i-2];printf("%d\n",A[i-1]);}}return 0;}Problem B:最大子段和Time Limit:1000MS Memory Limit:65536KTotal Submit:574 Accepted:299Description有一组数,如-2 5 4 -3 7 的最大子段和是13, 是从5到7.Input第一行输入一个n(1〈N〈=100 ) 表示这一组数有多长,第二行是N个数. 测试案例有多个,n=0时结束.Output输出这一组数的最大子段和.Sample Input5-2 5 4 -3 7109 -3 8 -28 98 -30 -20 50 -24 10Sample Output13 98分析: A-2 5 4 -3 7 B 表示A0~Ai 数段中包含第i 个元素的最大子段和-2 59613B[i]=??>+-=0]}[],[]1[max{0][i i A i A i B i i A#include int A[101]; int B[101]; int main() {int n,i,max;scanf("%d",&n); while(n!=0) {for(i=0;i<="">return 0; }Problem C:最长公共子序列Time Limit:1000MS Memory Limit:65536KTotal Submit:164 Accepted:99Description我们称序列Z=是序列X=的子序列当且仅当存在严格上升的序列,使得对j=1,2,...k,有Xij=zj.比如Z=<a,b,f,c>是X=<a,b,c,f,b,c>的子序列.现在给出两个序列X和Y,任务是找到X和Y的最大公共子序列,也就是说要找到一个最长的序列Z,使得Z既是X的子序列也是Y的子序列.Input输入包括多组测试数据.每组数据包括一行,给出两个长度不超过200的字符串,表示两个序列.两个字符串之间由若干个空格9开.Output对每组输入数据,输出一行,给出两个序列的最大公共子序列的长度.Sample Inputabcfbc abfcabprogramming contestabcd mnpSample Output42分析Z[i][j]=[1][1]1[][]max{[1][],[][1]}[][]Z i j X i Y jZ i j Z i j X i Y j--+=--≠下标0 1 2 3 4 5 6 Z[i][j] a b c f b c0 0 0 0 0 0 0 01 a 0 1 1 1 1 1 12 b 0 1 2 2 2 2 23 f 0 1 2 2 3 3 34 c 0 1 2 3 3 3 45 a 0 1 2 3 3 3 46 b 0 1 2 3 3 4 4X,Y下标从0开始,Z[i][j] 下标有效的从1开始#include#includechar x[201];char y[201];int z[200][200];int main(){int i,j,s,t,max;while(scanf("%s%s",x,y)!=EOF){s=strlen(x);t=strlen(y);for(i=0;i<s;i++)< p="">z[i][0]=0;for(j=0;j<t;j++)< p="">z[0][j]=0;for(i=1;i<=s;i++)for(j=1;j<=t;j++){if(x[i-1]==y[j-1]) z[i][j]=z[i-1][j-1]+1;else{if(z[i-1][j]>=z[i][j-1]) z[i][j]=z[i-1][j];else z[i][j]=z[i][j-1];}}max=z[0][0];for(i=0;i<=s;i++)for(j=0;j<=t;j++)if(z[i][j]>max) max=z[i][j];printf("%d\n",max);}return 0;}Problem D:最长上升子序列Time Limit:1000MS Memory Limit:65536KTotal Submit:456 Accepted:239 Description一个数的序列bi,当b1<=b2<=b3..<=bn的时候,称这个序列是上升的。
ACM动态规划算法
29 19 10
21 4
16
数塔及动态规划过程数据
总结
动态规划=贪婪策略+递推(降阶)+存储递推结果 贪婪策略、递推算法都是在“线性”地解决问题,而动态 规划则是全面分阶段地解决问题。可以通俗地说动态规划是 “带决策的多阶段、多方位的递推算法”。
1 认识动态规划
在动态规划算法策略中:
体现在它的决策不是线性的而是全面考虑不同的情况分别
以上的决策结果将五阶数塔问题变为4阶子问题,递推 出第四层与第五层的和为:
21(2+19),28(18+10),19(9+10),21(5+16)。
用同样的方法还可以将4阶数塔问题,变为3阶数塔问题。 …… 最后得到的1阶数塔问题,就是整个问题的最优解。
2.数据结构设计 1) 原始信息存储 原始信息有层数和数塔中的数据,层数用一个整型
3. 设计动态规划算法的基本步骤
设计一个标准的动态规划算法的步骤: 1) 划分阶段 划分阶段是运用动态规划求解多阶段决策问题的第一步, 在确定多阶段特性后,按时间或空间先后顺序,将过程划分 为若干相互联系的阶段。对于静态问题要人为地赋予“时间” 概念,以便划分阶段。 2) 选择状态 选择变量既要能确切描述过程演变又要满足无后效性, 而且各阶段状态变量的取值能够确定。一般地,状态变量的 选择是从过程演变的特点中寻找。 3) 确定决策并写出状态转移方程 通常选择所求解问题的关键变量作为决策变量,同时要 给出决策变量的取值范围
算法设计与分析
--动态规划算法
学习目标及内容
学习目 标 理解动态规划算法原理 掌握态规划算法应用
重点难点 动态规划原理 多阶段动态规划问题
动态规划算法
ACM 算法模板
ACM Standard Code LibraryHuang WeiComputer Science and EngineeringAssociation of ProgramingInformation Engineering CollegeHangzhou Dianzi UniversityApril, 2007ACM 算法模板集Contents一.常用函数与STL二.重要公式与定理1. Fibonacci Number2. Lucas Number3. Catalan Number4. Stirling Number(Second Kind)5. Bell Number6. Stirling's Approximation7. Sum of Reciprocal Approximation8. Young Tableau9. 整数划分10. 错排公式11. 三角形内切圆半径公式12. 三角形外接圆半径公式13. 圆內接四边形面积公式14. 基础数论公式三.大数模板四.数论算法1. Greatest Common Divisor最大公约数2. Prime素数判断3. Sieve Prime素数筛法4. Module Inverse模逆元5. Extended Euclid扩展欧几里德算法6. Modular Linear Equation模线性方程(同余方程)7. Chinese Remainder Theorem中国余数定理五.图论算法1. 最小生成树(Kruscal算法)2. 最小生成树(Prim算法)3. 单源最短路径(Bellman-ford算法)4. 单源最短路径(Dijkstra算法)5. 全源最短路径(Folyd算法)6. 拓扑排序7. 网络预流和最大流8. 网络最小费用最大流9. 网络最大流(高度标号预流推进)10. 最大团11. 最大二分图匹配(匈牙利算法)六.几何算法1. 几何模板2. 球面上两点最短距离3. 三点求圆心坐标七.专题讨论1. 树状数组2. 字典树3. 后缀树4. 线段树5. 并查集6. 二叉堆7. 逆序数(归并排序)8. 树状DP9. 欧拉路10. 八数码11. 高斯消元法12. 字符串匹配(KMP算法)13. 全排列,全组合第一章常用函数和STL一.常用函数#include <stdio.h>int getchar( void ); //读取一个字符, 一般用来去掉无用字符char *gets( char *str ); //读取一行字符串#include <stdlib.h>void * malloc( size_t size ); //动态内存分配, 开辟大小为 size 的空间void qsort( void *buf, size_t num, size_t size, int (*compare)(const void *, const void *) ); //快速排序Sample:int compare_ints( const void* a, const void* b ){int* arg1 = (int*) a; int* arg2 = (int*) b;if( *arg1 < *arg2 ) return -1;else if( *arg1 == *arg2 ) return 0;else return 1;}int array[] = { -2, 99, 0, -743, 2, 3, 4 }; int array_size = 7;qsort( array, array_size, sizeof(int), compare_ints );#include <math.h>//求反正弦, arg∈[-1, 1], 返回值∈[-pi/2, +pi/2]double asin( double arg );//求正弦, arg为弧度, 弧度=角度*Pi/180.0, 返回值∈[-1, 1]double sin( double arg );//求e的arg次方double exp( double arg );//求num的对数, 基数为edouble log( double num );//求num的根double sqrt( double num );//求base的exp次方double pow( double base, double exp );#include <string.h>//初始化内存, 常用来初始化数组void* memset( void* buffer, int ch, size_t count );memset( the_array, 0, sizeof(the_array) );//printf是它的变形, 常用来将数据格式化为字符串int sprintf( char *buffer, const char *format, ... );sprintf(s, "%d%d", 123, 4567); //s="1234567"//scanf是它的变形, 常用来从字符串中提取数据int sscanf( const char *buffer, const char *format, ... );Sample:char result[100]="24 hello", str[100]; int num;sprintf( result, "%d %s", num,str );//num=24;str="hello" ;//字符串比较, 返回值<0代表str1<str2, =0代表str1=str2, >0代表str1>str2 int strcmp( const char *str1, const char *str2 );二.常用STL[标准container概要]vector<T> 大小可变的向量, 类似数组的用法, 容易实现删除list<T> 双向链表queue<T> 队列, empty(), front(), pop(), push()stack<T> 栈, empty(), top(), pop(), push()priority_queue<T> 优先队列, empty(), top(), pop(), push()set<T> 集合map<key,val> 关联数组, 常用来作hash映射[标准algorithm摘录]for_each() 对每一个元素都唤起(调用)一个函数find() 查找第一个能与引数匹配的元素replace() 用新的值替换元素, O(N)copy() 复制(拷贝)元素, O(N)remove() 移除元素reverse() 倒置元素sort() 排序, O(N log(N))partial_sort() 部分排序binary_search() 二分查找merge() 合并有序的序列, O(N)[C++ String摘录]copy() 从别的字符串拷贝empty() 判断字符串是否为空erase() 从字符串移除元素find() 查找元素insert() 插入元素length() 字符串长度replace() 替换元素substr() 取子字符串swap() 交换字符串第二章重要公式与定理1.Fibonacci Number0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610 …Formula:2.Lucas Number1, 3, 4, 7, 11, 18, 29, 47, 76, 123...Formula:3.Catalan Number1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012…Formula:Application:1)将n + 2 边形沿弦切割成n个三角形的不同切割数Sample:n = 2;n = 3;2)n + 1个数相乘, 给每两个元素加上括号的不同方法数Sample:n = 2; (1 (2 3)), ((1 2) 3)n = 3; (1 (2 (3 4))), (1 ((2 3) 4)) , ((1 2) (3 4)), ((1 (2 3)) 4), (((1 2) 3) 4)3)n 个节点的不同形状的二叉树数(严《数据结构》P.155)4)从n * n 方格的左上角移动到右下角不升路径数Sample:n = 2;n = 3;4.Stirling Number(Second Kind)S(n, m)表示含n个元素的集合划分为m个集合的情况数或者是n个有标号的球放到m 个无标号的盒子中, 要求无一为空, 其不同的方案数Formula:Special Cases:5.Bell Numbern 个元素集合所有的划分数Formula:6.Stirling's Approximation7.Sum of Reciprocal ApproximationEulerGamma = 0.57721566490153286060651209;8.Young TableauYoung Tableau(杨式图表)是一个矩阵, 它满足条件:如果格子[i, j]没有元素, 则[i+1, j]也一定没有元素如果格子[i, j]有元素a[i, j],则[i+1, j]要么没有元素, 要么a[i+1, j] > a[i, j] Y[n]代表n个数所组成的杨式图表的个数Formula:Sample:n = 3;9.整数划分将整数n分成k份, 且每份不能为空, 任意两种分法不能相同1) 不考虑顺序for(int p=1; p<=n ;p++)for(int i=p; i<=n ;i++)for(int j=k; j>=1 ;j--)dp[i][j] += dp[i-p][j-1];cout<< dp[n][k] <<endl;2) 考虑顺序dp[i][j] = dp[i-k][j-1]; (k=1..i)3) 若分解出来的每个数均有一个上限mdp[i][j] = dp[i-k][ j-1]; (k=1..m)10.错排公式11.三角形内切圆半径公式12.三角形外接圆半径公式13.圆內接四边形面积公式14.基础数论公式1)模取幂2) n的约数的个数若n满足, 则n的约数的个数为第三章大数模板/**** **** **** **** **** ***** Function Name : BigNumber* Description : BigNumber's HPC* Author : HuangWei* Last Edited : 07.4.11**** **** **** **** **** ****/#include <iostream>#include <string>#include <sstream>#include <memory>#include <algorithm>#define BASE 1000 // 基数#define DIG 1100 // 存储using namespace std;class BigNumber{private:int data[DIG]; // 数据区int len; // 记录长度public:BigNumber() {len=1;memset(data,0,sizeof(data));data[0]=1;}BigNumber(int); // 输入默认十进制BigNumber(char*);BigNumber(const BigNumber &);// 类型转换BigNumber & Num_BNum(int); //把一个整数转换成BigNumber型的BigNumber & Str_BNum(char*); //把一个字符串类型的转换成BigNumber型的int Int();string Str();// HPCBigNumber & Add(const BigNumber &);BigNumber & Sub(const BigNumber &);BigNumber & Mul(const BigNumber &);BigNumber & Div(int);BigNumber & Mod(int);BigNumber & operator=(const BigNumber &);int Bigger(const BigNumber &) const;BigNumber operator + (const BigNumber &);BigNumber operator - (const BigNumber &);BigNumber operator * (const BigNumber &);BigNumber operator / (int);BigNumber operator % (int);BigNumber & operator += (const BigNumber &); BigNumber & operator -= (const BigNumber &); BigNumber & operator *= (const BigNumber &); BigNumber & operator /= (int);BigNumber & operator %= (int);};BigNumber & BigNumber::Num_BNum(int b){len=1; memset(data,0,sizeof(data));data[0] = 1;if(b < 0) {b = -b;data[0] = -1;}while(b > 0) {data[ len++ ] = b % BASE;b /= BASE;}return *this;}BigNumber & BigNumber::Str_BNum(char* sb) {int t=0, d=1, b=0, slen=strlen(sb), i;len=1; memset(data,0,sizeof(data));data[0] = 1;if(sb[0] == '-') data[0] = -1, b=1;for(i=slen-1; i>=b ;i--) {while(t >= BASE || d > BASE) {data[ len++ ] = t % BASE;t /= BASE;d = 10;}t += (sb[i]-'0') * d;d *= 10;}while(t > 0) {data[ len++ ] = t % BASE;t /= BASE;}return *this;}int BigNumber::Int(){istringstream sin;int v;sin.str( this->Str() );sin >> v;return v;} //这个函数的用法还是第一次看到,没看懂string BigNumber::Str(){int i,base_len=0;ostringstream sout;if(len == 1) {sout << '0';//sout << endl;return sout.str();}if(data[0] < 0) sout << "-";sout << data[len-1];i = BASE;while(i > 1) {base_len++;i /= 10;}for(i=len-2; i>0 ;i--) {sout.width(base_len);sout.fill('0');sout << data[i];}//sout << endl;return sout.str();} //这个函数也没有看懂BigNumber::BigNumber(int b){this->Num_BNum(b);}BigNumber::BigNumber(char* sb){this->Str_BNum(sb);}// -1 a<b, 0 a==b, 1 a>bBigNumber::BigNumber(const BigNumber & b){len = b.len; memcpy(data,b.data,sizeof(data));}int BigNumber::Bigger(const BigNumber & b) const {int i,flag;if(data[0] ==1 && b.data[0] ==1) flag = 1;else if(data[0] ==1 && b.data[0] ==-1) return 1;else if(data[0] ==-1 && b.data[0] ==1) return -1;else flag = -1;if(len > b.len) return flag;else if(len == b.len) {for(i=len-1; i>0 ;i--)if(data[i] > b.data[i]) return flag;}if(i == 0) return 0;return -flag;} //比较函数BigNumber & BigNumber::Add(const BigNumber & b) {int i;if(data[0] * b.data[0] != 1) {data[0] = -data[0];Sub(b);data[0] = -data[0];return *this;}len= len > b.len ? len : b.len;for(i=1; i<len ;i++) {data[i] += b.data[i];if(data[i] >= BASE) {data[i+1]++;data[i] -= BASE;}}if(data[i] > 0) len = i+1;return *this;} //加上b这个大数BigNumber & BigNumber::Sub(const BigNumber & b) {int i;if(data[0] * b.data[0] != 1) {data[0] = -data[0];Add(b);data[0] = -data[0];return *this;}len= len > b.len ? len : b.len;for(i=1; i<len ;i++) {data[i] -= b.data[i];if(data[i] < 0) {data[i+1]--;data[i] += BASE;}}if(data[len] < 0) {for(i=0; i<=len ;i++)data[i] = -data[i];for(i=1; i<len ;i++)if(data[i] < 0) {data[i+1]--;data[i] += BASE;}}while(data[len-1] == 0) len--;return *this;}BigNumber & BigNumber::Mul(const BigNumber & b) {BigNumber bt;int i,j,up;int temp,temp1;bt.data[0] = data[0] * b.data[0];for(i=1; i<len ;i++) {up = 0;for(j=1; j<b.len ;j++) {temp = data[i] * b.data[j] + bt.data[i+j-1] + up;if(temp >= BASE) {temp1 = temp % BASE;up = temp / BASE;bt.data[i+j-1] = temp1;}else {up = 0;bt.data[i+j-1] = temp;}}if(up != 0) bt.data[i+j-1] = up;}bt.len = i+j;while(bt.data[bt.len-1] == 0) bt.len--;*this=bt;return *this;}BigNumber & BigNumber::Div(int b){BigNumber bt;int i,down = 0;if(b < 0) bt.data[0] = -data[0] , b = -b;else bt.data[0] = data[0];for(i=len-1; i>=1 ;i--) {bt.data[i] = (data[i] + down * BASE) / b;down = data[i] + down * BASE - bt.data[i] * b;}bt.len = len;while(bt.data[bt.len-1] == 0) bt.len--;*this=bt;return *this;}BigNumber & BigNumber::Mod(int b){int temp = 0, up = 0, i;for(i=len-1; i>=1 ;i--) {temp = data[i];temp += up * BASE;up = temp % b;}if(data[0] < 0) up = -up;*this = up;return *this;}BigNumber & BigNumber::operator = (const BigNumber & b) {len = b.len; memcpy(data,b.data,sizeof(data)); return *this;}BigNumber BigNumber::operator + (const BigNumber & b) {BigNumber bt=*this; return bt.Add(b);}BigNumber BigNumber::operator - (const BigNumber & b) {BigNumber bt=*this; return bt.Sub(b);}BigNumber BigNumber::operator * (const BigNumber & b) {BigNumber bt=*this; return bt.Mul(b);}BigNumber BigNumber::operator / (int b){BigNumber bt=*this; return bt.Div(b);}BigNumber BigNumber::operator % (int b){BigNumber bt=*this; return bt.Mod(b);}BigNumber & BigNumber::operator += (const BigNumber & b) {return this->Add(b);}BigNumber & BigNumber::operator -= (const BigNumber & b) {return this->Sub(b);}BigNumber & BigNumber::operator *= (const BigNumber & b) {return this->Mul(b);}BigNumber & BigNumber::operator /= (int b){return this->Div(b);}BigNumber & BigNumber::operator %= (int b){return this->Mod(b);}第四章数论算法1.Greatest Common Divisor最大公约数int GCD(int x, int y){int t;while(y > 0) {t = x % y;x = y;y = t;}return x;}2.Prime素数判断bool is_prime(int u){if(u == 0 || u == 1) return false;if(u == 2) return true;if(u%2 == 0) return false;for(int i=3; i <= sqrt(u) ;i+=2)if(u%i==0) return false;return true;}3.Sieve Prime素数筛法const int M = 1000; // M : sizebool mark[M]; // true : prime numbervoid sieve_prime(){memset(mark, true, sizeof(mark));mark[0] = mark[1] = false;for(int i=2; i <= sqrt(M) ;i++) {if(mark[i]) {for(int j=i*i; j < M ;j+=i)mark[j] = false;}}}4.Module Inverse模逆元// ax ≡ 1 (mod n)int Inv(int a, int n){int d, x, y;d = extended_euclid(a, n, x, y);if(d == 1) return (x%n + n) % n;else return -1; // no solution}5.Extended Euclid扩展欧几里德算法//如果GCD(a,b) = d, 则存在x, y, 使d = ax + by// extended_euclid(a, b) = ax + byint extended_euclid(int a, int b, int &x, int &y){int d;if(b == 0) {x = 1; y = 0; return a;}d = extended_euclid(b, a % b, y, x);y -= a / b * x;return d;}6.Modular Linear Equation模线性方程(同余方程) //如果GCD(a, b)不能整除c, 则ax + by = c 没有整数解// ax ≡ b (mod n) n > 0//上式等价于二元一次方程ax – ny = bvoid modular_linear_equation(int a, int b, int n){int d, x, y, x0;d = extended_euclid(a, n, x, y);if( b%d == 0) {x0 = ( x*(b/d) ) % n; // x0 : basic solutionint ans = n;for(int i=0; i < d ;i++) {ans = ( x0 + i*(n/d) ) % n;cout << ans << endl;}}else cout << "no solution" << endl;}7.Chinese Remainder Theorem中国余数定理// x ≡ b[i] (mod w[i]), i∈[1, len-1]// 前提条件w[i] > 0, 且w[]中任意两个数互质int chinese_remainder(int b[], int w[], int len){int i, d, x, y, m, n;x = 0; n = 1;for(i=0; i < len ;i++) n *= w[i];for(i=0; i < len ;i++) {m = n / w[i] ;d = extended_euclid(w[i], m, x, y);x = (x + y*m*b[i]) % n;}return (n + x%n) % n;}第五章图论算法1.最小生成树(Kruscal算法)/**** **** **** **** **** ***** Function Name : 最小生成树(Kruscal算法)* Description : ZJU 1203 Swordfish O(E*LogE)**** **** **** **** **** ****/#include <iostream>#include <algorithm>#include <cstdio>#include <cmath>using namespace std;struct struct_edges{int bv,tv; //bv 起点 tv 终点double w; //权值};struct_edges edges[10100]; //边集struct struct_a{double x;double y;};struct_a arr_xy[101];int point[101],n,e; //n 顶点数, e 边数(注意是无向网络)double sum;int kruscal_f1(int point[], int v){int i = v;while(point[i] > 0) i = point[i];return i;}bool UDlesser(struct_edges a, struct_edges b){return a.w < b.w;}void kruscal() //只需要准备好n,e,递增的边集edges[]即可使用{int v1,v2,i,j;for(i=0; i<n ;i++) point[i]=0;i = j = 0;while(j<n-1 && i<e) {v1 = kruscal_f1(point, edges[i].bv);v2 = kruscal_f1(point, edges[i].tv);if(v1 != v2) {sum += edges[i].w; //注意sum初始为0point[v1]=v2;j++;}i++;}}int main(){int k,i,j;cin>>n;k=0;while(n != 0) {sum=0;k++;for(i=0; i<n ;i++)cin>>arr_xy[i].x>>arr_xy[i].y;e=0;for(i=0; i<n ;i++) //从0开始计数for(j=i+1; j<n ;j++) //注意是无向网络{if(i == j) continue;edges[e].bv=i;edges[e].tv=j;edges[e].w=sqrt((arr_xy[i].x-arr_xy[j].x)*(arr_xy[i].x-arr_xy[j].x)+( arr_xy[i].y-arr_xy[j].y)*(arr_xy[i].y-arr_xy[j].y));e++;}sort(edges,edges+e,UDlesser); //得到一个递增的边集,注意是从0开始计数kruscal();printf("Case #%d:\n",k); //cout<<"Case #"<<k<<":"<<endl;printf("The minimal distance is: %.2f\n",sum); //输出sumcin>>n;if(n != 0) printf("\n");}}2.最小生成树(Prim算法)/**** **** **** **** **** ***** Function Name : 最小生成树(Prim算法)* Description : ZJU 1203 Swordfish O(N^2)**** **** **** **** **** ****/#include <iostream>#include <cmath>#include <cstdio>using namespace std;double sum, arr_list[101][101], min;int i, j, k=0, n;struct struct_a{float x;float y;};struct_a arr_xy[101];struct struct_b{int point;float lowcost;};struct_b closedge[101];void prim(int n) //prim 需要准备:n顶点数 arr_list[][]顶点的邻接矩阵也是从0开始计数{int i,j,k;k=0;for(j=0; j<n ;j++) {if(j != k) {closedge[j].point = k;closedge[j].lowcost = arr_list[k][j];}}closedge[k].lowcost=0;for(i=0; i<n ;i++) {min=10000;for(j=0; j<n ;j++) {if (closedge[j].lowcost != 0 && closedge[j].lowcost < min) {k = j;min = closedge[j].lowcost;}}sum += closedge[k].lowcost; //不要改成sum+=min; sum即为所求值 closedge[k].lowcost = 0;for(j=0; j<n ;j++) {if(arr_list[k][j] < closedge[j].lowcost) {closedge[j].point = k;closedge[j].lowcost = arr_list[k][j];}}}}/*arr_list[][]= Wij 如果Vi, Vj有边0 如果i=j无限大如果没有边*/int main(){cin>>n;while(n != 0) {sum=0;k++;for(i=0; i<n ;i++)cin>>arr_xy[i].x>>arr_xy[i].y;for(i=0; i<n ;i++)for(j=0; j<n ;j++) //得到邻接矩阵arr_list[][]arr_list[i][j]=arr_list[j][i]=sqrt((arr_xy[i].x-arr_xy[j].x)*(arr_xy[i].x-arr_xy[j].x)+(arr_xy[i].y-arr_xy[j].y)*(arr_xy[i].y-arr_xy[j].y));prim(n);cout<<"Case #"<<k<<":"<<endl;printf("The minimal distance is: %.2f\n",sum);cin>>n;if(n!=0) printf("\n");}}3.单源最短路径(Bellman-ford算法)/**** **** **** **** **** ***** Function Name : 单源最短路径(Bellman-ford算法)* Description : 可允许有负权**** **** **** **** **** ****/#include <stdio.h>#define MAX 100#define MAXNUM 1000000typedef struct graphnode{int vexnum; //顶点数int arcnum; //边数int gra[MAX][MAX]; //图}Graph;Graph *G;//arc数组中存储的第一个顶点到其他顶点的最短路径//结果存在dis数组中int dis[MAX];int arc[MAX][MAX];void bellman(Graph *G){int i,j;bool sign;for(i=0; i < G->vexnum ;i++) dis[i]=MAXNUM;dis[1] = 0;sign = true;for(i=1; i < G->vexnum ;i++) {sign = false;for(j=0; j < G->arcnum ;j++) {if(dis[ arc[j][0] ] < MAXNUM&& dis[ arc[j][1] ] > dis[ arc[j][0] ] + G->gra[ arc[j][0] ][ arc[j][1] ]) {dis[ arc[j][1] ]=dis[ arc[j][0] ] + G->gra[ arc[j][0] ][ arc[j][1] ];sign = true;}}}return;}4.单源最短路径(Dijkstra算法)/**** **** **** **** **** ***** Function Name : 单源最短路径 (Dijkstra算法)* Description : 贪心, O(N^2), 不能有负权**** **** **** **** **** ****/int matrix[200][200],n; //matrix[][], 30000表示无限大,即无边.否则为有边,其值为边的权值void Dijkstra(int x,int y) //起点Vx 终点Vy{int i,j,k,path[40000],mark[40000];int min,dist[40000];for(i=1;i<=n;i++) {mark[i] = 0;dist[i] = matrix[x][i];path[i] = x;}mark[x] = 1;do {min=30000;k=0;for(i=1;i<=n;i++)if(mark[i]==0 && dist[i]<min) {min = dist[i];k = i;}if(k) {mark[k] = 1;for(i=1;i<=n;i++)if(matrix[k][i]<30000 && min+matrix[k][i]<dist[i]) {dist[i] = min + matrix[k][i];path[i] = k;}}}while(k);cout<<dist[y]<<endl; //dist[y] 的值就是从Vx 到 Vy 的最短路径值//如果希望得到路径,加入如下代码:do {cout<<k<<"<--";k = path[k];}while(k!=x);cout<<x<<endl;}5.全源最短路径(Folyd算法)/**** **** **** **** **** ***** Function Name : 全源最短路径(Folyd算法)* Description : DP, O(N^3)**** **** **** **** **** ****///初始化//min_graph[i][j]=graph[i][j];//path[i][j]=j;void Floyd(){int i,j,k;for(k=0;k<vertex_number;k++) {for(i=0;i<vertex_number;i++) {for(j=0;j<vertex_number;j++) {if((graph[i][k]==-1) || (graph[k][j]==-1)) continue;if((min_graph[i][j]==-1) || (min_graph[i][j] > graph[i][k]+graph[k][j])) {min_graph[i][j] = graph[i][k]+graph[k][j]; /*最短路径值*/path[i][j] = k; /*最短路径*/}}}}}6.拓扑排序/**** **** **** **** **** ***** Function Name : 拓扑排序**** **** **** **** **** ****///degree[] 每个结点的入度//f[] 每个结点所在的层void Toplogical_sort(){int i,j;bool p=true;top=0;while(p) {p=false;top++;for(i=1;i<=n;i++)if(degree[i]==0) {p=true;f[i]=top;}for(i=1;i<=n;i++)if(f[i]==top) {for(j=1;j<=n;j++)if(map[i][j]) degree[j]--;degree[i]=-1;}}top--;}7.网络预流和最大流int rel[1000][10000]; //全局变量int pre[1000];//计算网络流//如果是二分图的匹配, 可以先对其进行网络预流以简化后续的查找int pre_flow(int n,vector<int> * v){int ret = 0;int i,j,t,t1;for(i = 0 ; i < v[0].size() ; i++){t = v[0][i]; //t是与节点0相邻接的点for(j = 0 ; j < v[t].size() ; j++){t1 = v[t][j]; //与t相邻接的点if(rel[t1][n - 1] > 0){ret++;rel[0][t]--, rel[t][0]++;rel[t][t1]--, rel[t1][t]++;rel[t1][n - 1]--, rel[n - 1][t1]++;break;}}}return ret;}/*网络中求最大流参数含义: n代表网络中节点数,第0节点为源点, 第n-1节点为汇点rel是个二维数组, rel[i][j]代表从节点i到节点j的流量v[]是一个节点数组, v[i]包含与节点i相邻接的所有节点返回值: 最大流量*/int max_flow(int n,vector<int> * v){int ret = 0,i;int t,t1,tm;queue<int> q;const int Infinite = 2000000000;while(1){for(t = 0 ; t < n ; t++) pre[t] = -1;while(!q.empty()) q.pop();q.push(0);while(!q.empty()){ //find a augmenting path using breath-first searcht = q.front();q.pop();if(t == n - 1) break; //到达汇点for(i = 0 ; i < v[t].size() ; i++){ //对于t相邻接的所有点查找可行路径 t1 = v[t][i];if(rel[t][t1] > 0 && pre[t1] == -1){pre[t1] = t;q.push(t1);}}}if(q.empty() && t != n - 1) break;tm = Infinite; //此处寻找路径最小值在二分图中可省略while(t != 0){ //find the minimal num in the patht1 = pre[t];if(rel[t1][t] < tm) tm = rel[t1][t];t = t1;}// tm = 1; //二分图中t = n - 1;while(t != 0){ //change the relationt1 = pre[t];rel[t1][t] -= tm;rel[t][t1] += tm;t = t1;}ret += tm;}return ret;}8.网络最小费用最大流/**** **** **** **** **** ****网络中最小费用最大流参数含义: np代表网络中的总节点数, v是网络节点的邻接表cost为最后求得的最小费用, mf为求得的最大流算法: 初始最小费用及最大流均为0,不断寻找可增广路增广路对应的单位费用最小并且可流修改残留网络及cost,mf. 直到无可增广路为止。
浙江大学acm程序设计竞赛动态规划讲义
最
优
三
角
如果没有红色虚线的部分,或许你会
形
认为决策应该是枚举子多边形内的
划 分
两点连线,然后分成两个子多边形. 这显然是不行的,因为计算机已经无 法再表示分割出来的子多边形了(不
能用f[i,j]来表示了).
那么我们该如何决策呢?寻找定量!
显然可以发现,f[i,j]表示的子多边形
最
有一条边是在内部的(黑色虚线),而这 一条边在该子多边形内必定属于某个
end;
end;
动 规
有时候当前状态确定后,以前状 态就已经确定,则无需枚举.
的
要
诀
-
状
态
Tom是一个非常有创业精神的人,由于大
学学的是汽车制造专业,所以毕业后他
用有限的资金开了一家汽车零件加工厂,
专门为汽车制造商制造零件。由于资金
有限,他只能先购买一台加工机器。现
在他却遇到了麻烦,多家汽车制造商需
拦
每个导弹有一定的高度,当前状态
截 导
就是以第i个导弹为最后一个打的导
弹。以前状态就是在这个导弹以前 打的那个导弹。
弹
显然这是十分能够体现状态间的联
系的题目。
最
长
给出两个字符串序列。求出这 样的一个最长的公共子串:子
公
串中的每个字符都能在两个原
共
串中找到,而且每个字符的顺
子
序和原串中的顺序一致。
费情况下,每个车站的以前状态车站一
定是递增的序列.这里是只要O(N)的程
买
序:
车
for j:=1 to 3 do begin
票
k:=en-1; for i:=en downto be do
ACM动态规划算法 C语言
其中的云算符为”+”时,显然有: a+c<=m<=b+d 当其中的运算符为“*”时,显然有: min{ac,ad,bc,bc}<=m<=max{ax,ad,bc,bd} 设m[i,j,0]表示链p[i][j]合并后的最小值, m[I,j,1]表示链 p[i][j]合并后的最大值。若最优合并在op[i+s]处,则 当op[i+s]为“+”时, m[i,j,0]=a+c; m[i,j,1]=b+d; 当op[i+s]为“*”时: m[I,j,0]=min{ac,ad,bc,bd} m[I,j,1]=max{ac,ad,bc,bc} 因此有下面的递推式成立:
如果该链最后一次合并运算发生在运算符op[i+s]处,则将 原链分割成两个部分,设m1表示对前一个子链采用任意方式 合并得到的值,a和b分别表示所有可能值中的最大值和最小 值。M2表示对后一个子链采用任意方式合并后得到的值,c 和d表示合并后的最大值和最小值。这样两个子链合并后的 值为:
m=(m1) op[i+s] (m2)
m[I,j,0]=min{minf[i,j,s]}, 1<=I,j<=n, 1<=s<=j m[I,j,1]=max{maxf[I,j,s]}, 1<=I,j<=n, 1<=s<=j 其中minf(i,j,s)为在+和“*”运算时的最小值,maxf(I,j,s) 表示在“+”和“*”时的最大值。 这样只要计算1~j中的最大值就可以求得最后的结果。且 m[I,1,0]=v[i], 1<=i<=n m[I,1,1]=v[i], 1<=i<=n 其程序见PolyMax.cpp。 例6:电路布线。 已知某电路板上下两端分别有n个接线端子,上面的端子 只与下面的端子相连,他们之间的连线已知,请问应怎样布 线才能保证在一层中连最多的线且互不相交。 这个题实际上已经告诉你 上面的第几个端子会与下面的
ACM动态规划问题简易模板(C++可编译)
1、0-1背包#include <stdio.h>#include <stdlib.h>//背包问题/*测试数据:输入:8 238 4 5 1 6 6 7 37 8 3 3 4 9 6 2输出:1 0 1 0 1 0 1 1*/int num,c;int v[10];int w[10];int m[10][30];//设m[i][j],则表示在前i个物品中,背包大小是j的情况下,背包所装东西的最大价值void knapsack(){int n=num-1;int jmax,i,j;if(w[n]<c) jmax=w[n];else jmax=c;for(i=0;i<jmax;i++)m[n][i]=0;for(i=w[n];i<=c;i++)m[n][i]=v[n];for(i=n-1;i>0;i--){if(w[i]<c) jmax=w[i];else jmax=c;for(j=0;j<jmax;j++)m[i][j]=m[i+1][j];for(j=w[i];j<=c;j++){if(m[i+1][j]<m[i+1][j-w[i]]+v[i])m[i][j]=m[i+1][j-w[i]]+v[i];elsem[i][j]=m[i+1][j];}}m[0][c]=m[1][c];if(c>=w[0]){if(m[0][c]<m[1][c-w[0]]+v[0])m[0][c]=m[1][c-w[0]]+v[0];}}void trackback(int *x){int n=num-1;int i;for(i=0;i<n;i++){if(m[i][c]==m[i+1][c]) x[i]=0;else{x[i]=1;c=c-w[i];}}if(m[n][c]>0) x[n]=1;else x[n]=0;}int main(){int i,x[10],j;scanf("%d %d",&num,&c);for(i=0;i<num;i++)scanf("%d",&v[i]);for(i=0;i<num;i++)scanf("%d",&w[i]);knapsack();for(i=0;i<=c;i++) printf("%3d",i);printf("\n");for(i=0;i<num;i++){for(j=0;j<=c;j++)printf("%3d",m[i][j]);printf("\n");}trackback(x);for(i=0;i<num;i++)printf("%d ",x[i]);printf("\n");return 0;}2、KMP算法#include<iostream>#include<string.h>using namespace std;inline void BuildNext(const char* pattern, size_t length, unsigned int* next){unsigned int i, t;i = 1;t = 0;next[1] = 0;while(i < length + 1){while(t > 0 && pattern[i - 1] != pattern[t - 1]){t = next[t];}++t;++i;if(pattern[i - 1] == pattern[t - 1]){next[i] = next[t];}else{next[i] = t;}}//pattern末尾的结束符控制,用于寻找目标字符串中的所有匹配结果用while(t > 0 && pattern[i - 1] != pattern[t - 1]){t = next[t];}++t;++i;next[i] = t;}unsigned int KMP(const char* text, size_t text_length, const char* pattern, size_t pattern_length, unsigned int* matches){unsigned int i, j, n;unsigned int next[pattern_length + 2];BuildNext(pattern, pattern_length, next);i = 0;j = 1;n = 0;while(pattern_length + 1 - j <= text_length - i){if(text[i] == pattern[j - 1]){++i;++j;//发现匹配结果,将匹配子串的位置,加入结果if(j == pattern_length + 1){matches[n++] = i - pattern_length;j = next[j];}}else{j = next[j];if(j == 0){++i;++j;}}//返回发现的匹配数return n;}int main(){char a[20],b[20];int n1,n2,n;unsigned int match[100];cin>>a;n1=strlen(a);//待匹配串cin>>b;n2=strlen(b);//模板串n=KMP(a,n1,b,n2,match);cout<<n<<endl;for(int i=0;i<n;i++)cout<<match[i]<<' ';}3、最大子段和#include<iostream>#include<stdio.h>using namespace std;int main(){int T,n;int a[50000];int hd[50000],tl[50000];scanf("%d",&T);while(T--){scanf("%d",&n);int i,temp,max;;for(i = 0;i < n;i++)scanf("%d",&a[i]);//hd[],left -> rightmax = hd[0] = a[0];for(i = 1;i < n;i++){temp = a[i] + hd[i - 1];hd[i] = temp > a[i] ? temp : a[i];}for(i = 1;i < n;i++){hd[i] = max > hd[i] ? max : hd[i];max = hd[i];//tl[],right -> leftmax = tl[n - 1] = a[n - 1];for(i = n - 2;i >= 0;i--){temp = a[i] + tl[i + 1];tl[i] = temp > a[i] ? temp : a[i];}for(i = n - 2;i >= 0;i--){tl[i] = max > tl[i] ? max : tl[i];max = tl[i];}max = hd[0] + tl[1];for(i = 1;i < n - 1;i++){temp = hd[i] + tl[i + 1];max = max > temp ? max : temp;}printf("%d\n",max);}return 0;}4、最长公共子序列(不严格连续)#include <stdio.h>#include <string.h>#define MAXLEN 100void LCSLength(char *x, char *y, int m, int n, int c[][MAXLEN], int b[][MAXLEN]) {int i, j;for(i = 0; i <= m; i++)c[i][0] = 0;for(j = 1; j <= n; j++)c[0][j] = 0;for(i = 1; i<= m; i++){for(j = 1; j <= n; j++){if(x[i-1] == y[j-1]){c[i][j] = c[i-1][j-1] + 1;b[i][j] = 0;}else if(c[i-1][j] >= c[i][j-1]){c[i][j] = c[i-1][j];b[i][j] = 1;}else{c[i][j] = c[i][j-1];b[i][j] = -1;}}}}void PrintLCS(int b[][MAXLEN], char *x, int i, int j) {if(i == 0 || j == 0)return;if(b[i][j] == 0){PrintLCS(b, x, i-1, j-1);printf("%c ", x[i-1]);}else if(b[i][j] == 1)PrintLCS(b, x, i-1, j);elsePrintLCS(b, x, i, j-1);}int main(int argc, char **argv){char x[MAXLEN] = {"ABCBDAB"};char y[MAXLEN] = {"BDCABA"};int b[MAXLEN][MAXLEN];int c[MAXLEN][MAXLEN];int m, n;m = strlen(x);n = strlen(y);LCSLength(x, y, m, n, c, b);PrintLCS(b, x, m, n);return 0;}5、最长公共子序列(不严格连续)#include<iostream>#include<cstdio>#include<memory.h>using namespace std;const int N = 505;int num1[N],num2[N],f[N][N];int main(){int t,n,m;scanf("%d",&t);while(t--){scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&num1[i]);scanf("%d",&m);for(int j=1;j<=m;j++)scanf("%d",&num2[j]);memset(f,0,sizeof(f));int answer=0;int ma;for(int i=1;i<=n;i++){ma=0;for(int j=1;j<=m;j++){f[i][j]=f[i-1][j];if(num1[i]>num2[j]&&f[i-1][j]>ma)ma=f[i-1][j];if(num1[i]==num2[j])f[i][j]=ma+1;}}for(int j=0;j<=m;j++)answer=max(answer,f[n][j]);printf("%d\n",answer);if(t!=0)printf("\n");}return 0;}6、最大子矩阵和#include <iostream>#include<memory.h>using namespace std;//求最大连续子矩阵和,动态规划,O(n^3) of time:/*输入41 -4 3 -8-3 5 2 -32 -1 8 1-1 1 -2 -4输出14*/int max_sum(int n, int *arr){ //求单个序列的最大连续子串和int result=0;int b=0;for(int i=0;i<n;i++){if(b>0) b+=arr[i];else b=arr[i];if(b>result) result=b;}return result;}int max_sum2(int m, int n, int **arr){int result=0;int *b=new int[n];for(int i=0;i<m;i++){memset(b,0,sizeof(int)*n);for(int j=i;j<m;j++){for(int k=0;k<n;k++)b[k]+=arr[j][k];//b[k]=arr[i][k]+arr[i+1][k]+...+arr[j][k]//从例子来说,当i=1,j=2时,有b[k]=arr[1][k]+arr[2][k],这时取到maxint max=max_sum(n,b);if(max>result) result=max;}}delete b;return result;}int main(){int N;cin>>N;int i,j;int **arr=new int*[N];for(i=0;i<N;i++){arr[i]=new int[N];for(j=0;j<N;j++)cin>>arr[i][j];}cout<<max_sum2(N,N,arr)<<endl;for(i=0;i<N;i++)delete arr[i];delete arr;return 0;}7、石子合并问题#include <iostream>#include <stdio.h>using namespace std;//石头合并问题PKU 1086 动态规划/*输入:44 1 2 3输出:*/#define MAX 1000000000int a[202];//每个石头的重量long f[202][202];//f[i][j],第i个石头分到第j个石头合并的最小代价long sum[202][202];//sum[i][j],第i个石头到第j个石头的重量之和void print(int num){int i,j;for(i=1;i<=num;i++){for(j=1;j<=num;j++)printf("%3d",f[i][j]);cout<<endl;}cout<<endl;}void cal(int num){int i,j,k,min,d;for(i=1;i<=num;i++)f[i][i]=0;//不合并时的代价for(i=1;i<num;i++){sum[i][i]=a[i];for(j=i+1;j<=num;j++){sum[i][j]=sum[i][j-1]+a[j];}}sum[num][num]=a[num];for(d=1;d<=num-1;d++){for(i=1;i<=num-d;i++){j=i+d;min=MAX;//i..k为一堆石头,k+1,k+2...j为另一堆石头//f[i][j]为f[i][k]+f[k+1][j]+sum[i][j]的最小值(i<=j<k)for(k=i;k<j;k++)if(min>f[i][k]+f[k+1][j]+sum[i][j]) min=f[i][k]+f[k+1][j]+sum[i][j];f[i][j]=min;print(num);}}}int main(){int num,i;scanf("%d",&num);for(i=1;i<=num;i++)cin>>a[i];cal(num);cout<<f[1][num]<<endl;return 0;}8、最大乘积#include <iostream>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <math.h>using namespace std;//添加乘号得到最大乘积动态规划#define NMAX 12#define CMAX 7__int64 f[NMAX][CMAX];//f[i][j],长度为i,用了j个乘号后的最大值char str[22];void print(int num,int k){ //用于调试时打印f[][]int i,j;for(i=0;i<num;i++){for(j=1;j<=k;j++)printf("%6d",f[i][j]);cout<<endl;}cout<<endl;// system("pause");}int conv(int start,int num){ //在str[i]中,以start为起点,num为长度所表示的数字int sum,i;sum=0;for(i=1;i<=num;i++){sum*=10;sum+=str[start+i-1]-'0';}return sum;}void cal(int num,int chen){int i,j,temp,k;for(i=0;i<num;i++){ //初始化,不用乘号时的情况f[i][0]=conv(0,i+1);}for(j=1;j<=chen;j++){for(i=j;i<num;i++){temp=0;for(k=0;k<i;k++){//a1,a2,a3..an用j个乘号连接//看成是a1,a2...ak已经用j-1个乘号连接,//然后再与后面的ak+1,ak+2..an组成的数用1个乘号连接if(temp<f[k][j-1]*conv(k+1,i-k))temp=f[k][j-1]*conv(k+1,i-k);}f[i][j]=temp;//找到局部的最大乘积}// print(num,chen);}}int main(){int num,chen;//num为字符串长度while(scanf("%d%d",&num,&chen)!=EOF){scanf("%s",&str);cal(num,chen);printf("%I64d\n",f[num-1][chen]);}return 0;}。
动态规划II(含详细c语言代码)
if( i ==0 || j == 0 ) MaxLen(i, j) = 0 //两个空串的最长公共子序列长度是0 MaxLen(i, j) = MaxLen(i-1, j-1 ) + 1; else if( s1[i] == s2[j] ) else
MaxLen(i,j) = Max(MaxLen(i, j-1), MaxLen(i-1, j));
17/27
购物问题
1、问题描述
由于换季,ACM商场推出优惠活动,以超低价格出售 若干种商品。但是,商场为避免过分亏本,规定某些 商品不能同时购买,而且每种超低价商品只能买一件。 身为顾客的你想获得最大的实惠,也就是争取节省最 多的钱。经过仔细研究过,我们发现,商场出售的超 低价商品中,不存在以下这种情况: N(3<=n)种商品C1,C2,…,Cn ,其中Ci 和Ci+1 是不能 同时购买的(i=1,2,…,n-1),而且C1和Cn也不能同时 购买。 请编程计算可以节省的最大金额数。
14/27
int main(void) { int i, j, k; int t1, t2; int n, m; int nMinP_D; //辩控双方总分一样时的辩控差 int nCaseNo;//测试数据编号 nCaseNo=0; scanf("%d%d", &n, &m); while(n+m) { nCaseNo++; for(i=1;i<=n;i++) scanf("%d%d", &P[i], &D[i]); memset(f, -1, sizeof(f)); memset(Path, 0, sizeof(Path)); nMinP_D=m*20; //题目中的辩控差为0 //对应到程序中辩控差就是m*20 f[0][nMinP_D]=0; //选0 个人辩控差为0 的方案,其辩控和就是0
动态规划I(含详细c语言代码)
第九课
动态规划(I)
角形。从三角形的顶部到底部有很多条 不同的路径。对于每条路径,把路径上面的数加起来可以得到 一个和,和最大的路径称为最佳路径。你的任务就是求出最佳 路径上的数字之和。 注意:路径上的每一步只能从一个数走到下一层上和它最近的 左边的数或者右边的数。
return aMaxSum[r+1][j] +D[r][j]; return aMaxSum[r+1][j+1] + D[r][j]; }
10/49
4、参考程序 II
int main(void) {
int m; scanf("%d", & N); //将 aMaxSum 全部置成-1, 开始时所有的 MaxSum(r, j)都没有算过 memset(aMaxSum, -1, sizeof(aMaxSum)); for( int i = 1; i <= N; i ++ )
在题目中给出的例子里,如果我们将 MaxSum(r, j)被计算的次数都写在位置(r, j),那么就能得到右面的三角形:
7 38 810 2744 45265
1 11 121 1331 14641
8/49
程序分析 从上图可以看出,最后一行的计算次数总和是16,倒数第二行
的计算次数总和是8。不难总结出规律,对于N 行的三角形,总 的计算次数是2^0 +2^1+2^2+…+2^(N-1)=2^N-1。当 N= 100 时,总的计算次数是一个让人无法接受的大数字。
for( j = 1; j < i ; j ++ )
{ if( aMaxSum[i][j] > aMaxSum[i][j+1] )
动态规划——C编辑最短距离
动态规划——C编辑最短距离C - 编辑距离时间限制: 1000⼥⼠内存限制: 65536KB 64位输⼊输出格式: %I64d & %I64u提交描述Let x and y be two strings over some finite alphabet A. We would like to transform x into y allowing only operations given below: Deletion: a letter in x is missing in y at a corresponding position.Insertion: a letter in y is missing in x at a corresponding position.Change: letters at corresponding positions are distinctCertainly, we would like to minimize the number of all possible operations.IllustrationA G T A A G T * A G G C| | | | | | |A G T * C * T G A C G CDeletion: * in the bottom lineInsertion: * in the top lineChange: when the letters at the top and bottom are distinctThis tells us that to transform x = AGTCTGACGC into y = AGTAAGTAGGC we would be required to perform 5 operations (2 changes, 2 deletions and 1 insertion). If we want to minimize the number operations, we should do it likeA G T A A G T A G G C| | | | | | |A G T C T G * A C G Cand 4 moves would be required (3 changes and 1 deletion).In this problem we would always consider strings x and y to be fixed, such that the number of letters in x is m and the number of letters in y is n where n ≥ m.Assign 1 as the cost of an operation performed. Otherwise, assign 0 if there is no operation performed.Write a program that would minimize the number of possible operations to transform any string x into a string y.InputThe input consists of the strings x and y prefixed by their respective lengths, which are within 1000.OutputAn integer representing the minimum number of possible operations to transform any string x into a string y.Sample Input10 AGTCTGACGC11 AGTAAGTAGGCSample Output4题⽬⼤意:给出两个字符串X,Y,求出从X——>Y的最⼩操作次数,只可以删除,添加,修改⼀个字符。
ACM课件 动态规划
• 所有的海盗都乐于看到他们的一位同伙被扔 进海里,不过,如果让他们选择的话,他们 还是宁可得一笔现金。他们当然也不愿意自 己被扔到海里。
• 所有的海盗都是聪明绝顶的,而且知道其他 的海盗也是聪明绝顶的。
• 此外,没有两名海盗是同等厉害的——这些 海盗按照完全由上到下的等级排好了座次, 并且每个人都清楚自己和其他所有人的等级。
(4)C1,C2,C3是第二次输入结点,他们到D1, D2各有两种费用。此时应计算C1,C2,C3分别到E 的最少费用。 f(C1) =min{C1D1+ f(D1) ,C1D2+ f(D2)}。
• 3号海盗的分配方案:3号海盗分得99块 金子,2号海盗一无所获,1号海盗得1块 金子。
•1号海盗知道,如果3号的方案被否决,那么最后 将只剩2个海盗,而1号将肯定一无所获——此外, 3号也明白1号了解这一形势。因此,只要3号的分 配方案给1号一点甜头使他不至于空手而归,那么 不论3号提出什么样的分配方案,1号都将投赞成票。 因此3号需要分出尽可能少的一点金子来贿赂1号海 盗
• 4号的分配方案应是:99块金子归自己,3 号一块也得不到,2号得1块金子,1号也是 一块也得不到。
4号海盗的策略也差不多。他需要有50%的支 持票,因此同3号一样也需再找一人做同党。 他可以给同党的最低贿赂是1块金子,而他可 以用这块金子来收买2号海盗。因为如果4号被 否决而3号得以通过,则2号将一文不名。
• 除起点A和终点E外,其它各点既是上一阶 段的终点又是下一阶段的起点。
例若在如选第从择二AB阶2到的段B决,的策再第,从一BB阶22就段点是中出第,发一A,为阶对起段于点在B,2我点终们就点决有有策一B之个1,下可的供 B结选2果两择,个的它,终既因点是而集第这合一时(C阶走1,段的C路路2线,线的C有3终两);点个若,选选又择择是,由第一B二是2走阶走至段到C路B21为线, 一的第是始二走点阶到。段B的2。决策,则C2就是第二阶段的终点,同时又 是第三阶段的始点。
ACM5-动态规划
28
如何解决?
请发表见解
2018/8/7 29
小结:DP的基本思想
如果各个子问题不是独立的,不同的子问题 的个数只是多项式量级,如果我们能够保存已 经解决的子问题的答案,而在需要的时候再找 出已求得的答案,这样就可以避免大量的重复 计算。 由此而来的基本思路是——用一个表记录所 有已解决的子问题的答案,不管该问题以后是 否被用到,只要它被计算过,就将其结果填入 表中。
4个物品选一对?(如何利用前面的知识) n个物品选一对,…
n个物品选二对,… 最终问题:n个物品选k对,如何?(n>=2k)
2018/8/7
结论?
23
五、经典问题:1058 Humble Numbers
Problem Description
A number whose only prime factors are 2,3,5 or 7 is called a humble number. The sequence 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 24, 25, 27, ... shows the first 20 humble numbers. Write a program to find and print the nth element in this sequence
思考 1160 FatMouse's Speed
Sample Input
6008 6000 500 1000 1100 6000 8000 6000 2000
2018/8/7
Sample Output
1300 2100 2000 4000 3000 2000 1400 1200 1900
ACM动态规划算法_C语言.
显然上述算法的实现与前面的例子相同。如果希望求出其 最长公共子序列,可设置一个数组b[i][j],用于记录是哪一个 子序列求得的解。 当b[i][j]=1时,表示Zk是在原来Zk-1的基础上加上Xi或者Yj 得到,因为此时Xi=Yj。
当b[i][j]=2时,表示Xi和Yj的最长公共子序列与Xi-1和Yj 的 最长公共子序列相同。 当b[i][j]=3时,表示Xi和Yj的最长公共子序列与Xi和Yj 的 最长公共子序列相同。
可通过求得的b[i][j]然后再计算出其最后的子序列。当然 也可在求解过程中计算其最后的最序列。其程序见 MaxLength.cpp.
该算法还可作一定程度的改进以提高其运行速度。
例3:已知某整数序列A=(a1,a2,…,an),求该序列的最大 子段和。 分析:显然要求其最大子段和可通过一个3重循环求得。 首先把序列分解成两个部分,对于前一部分,我们已经计算 出其所有可能的组合结果,后一部分则分别计算其所有组合 中的最大值,并于前面求得的最大值进行比较,如果比前面 求得的最大值还大则取代前面的最大值。这样可求得其最大 子段和。 上述算法执行时间太长。可采用分治法求解,以降低时 间复杂度。 分治法的思想是将序列分解成两个相同的部分,显然可 得到如下几种情形: (1)整个序列的最大子段和与前一部分的最大子段和同。 (2)整个序列的最大子段和与后一部分的最大子段和同。
采用自底向上的计算方法进行计算。如上例中,可采用如下 的计算顺序: m[0][0]->m[1][1]->m[2][2]->m[3][3] m[0][1]->m[1][2]->m[2][3] m[0][2]->m[1][3] m[0][3] 从上面的计算顺序可以看出类似于一个上三角矩阵,先 计算斜线上的元素,并依次向上递推。 如果希望知道采用何种方式才能实现乘法次数最少,可用 一个数组s[i][j]来记录m[i][j]最优解时的k值。每一个m[i][j]对应 一个s[i][j],这样就可知道如何分解上述矩阵表达式以得到最 小的乘法次数了。上例中k值依次为0->2 在上例中,最后的分解结果为(A0[10][100]*(A1[100][50]* A2[50][2]))*A4[2][10]。
ACM 程序设计竞赛入门:第9讲 动态规划(2)
2020/12/10
4
例题2-1:最长递增子序列
i 012 3 4 5 6 7 8 Num[i] 1 4 7 2 5 8 3 6 9
2020/12/10
5
状态转移方程:
动态规划的状态表示描述为: m[i] ( 1≤i≤n ) 表 示 以 num[i] 结 尾 的 最 长
上升子序列的长度。
状态转移方程: m[i]=1+max{0,m[k]|x[k]<x[i],
证明:假设四个从小到大的数:a、b、c、 d,只需证明以下表达式成立即可:
(a-b)^2+(c-d)^2< (a-c)^2+(b-d)^2
(a-b)^2+(c-d)^2< (a-d)^2+(b-c)^2 ……(略)
2020/12/10
10
预备工作:
排序!
2020/12/10
11
第二感觉:
第九讲
动态规划(2)
(Dynamic programming)
2020/12/10
1
一、动态规划的基本思想
基础思想来自分治策略后面的直觉
人们通过细心地把问题分解成一系列子问题, 然后对越来越大的问题建立正确的解。
•不同的子问题的个数只是多项式量级; •可以容易地从子问题的解计算初始问题 的解; •在子问题从“最小”到“最大”。存在 一种自然的顺序,与一个容易计算的递 推式相联系。
1≤k<i } 问题的解: max{m[i],1≤i≤n},
2020/12/10
6
M[i]的计算:
i 012 3 4 5 6 7 8 Num[i] 1 4 7 2 5 8 3 6 9
m[i] 1 2 3 2 3 4 3 4 5
acm动态规划总结(1)
Pku acm 1163 the Triangle 动态规划题目总结(一)题目:对于一个有数字组成的二叉树,求由叶子到根的一条路径,使数字和最大,如:7388 1 02 7 4 44 5 2 6 5这个是经典的动态规划,也是最最基础、最最简单的动态规划,典型的多段图。
思路就是建立一个数组,由下向上动态规划,保存页子节点到当前节点的最大值,Java核心代码如下:for(int i=num-2;i>=0;i--){for(int j=0;j<=i;j++){总结:这道题是很地道的DP,因为它的子问题实在是太多了,所以将问题的结果保存起来,刘汝佳《算法艺术和信息学竞赛》中115页讲到自底向上的递推,这个例子就非常典型。
总体来说这个题目还是非常简单的,不过这个思想是地道的动态规划。
带有详细注释的代码可以在获得Pku acm 2081 Recaman's Sequence 动态规划题目总结(三)一道很简单的动态规划,根据一个递推公式求一个序列,我选择顺序的求解,即自底向上的递推,一个int数组result根据前面的值依此求出序列的每一个结果,另外一个boolean数组flag[i]记录i是否已经出现在序列中,求result的时候用得着,这样就避免了查找。
核心的java代码为:for(i=1;i<=500000;i++){if(result[i-1]-i>0&&flag[result[i-1]-i]==false){result[i] = result[i-1]-i;flag[result[i-1]-i] = true;}else{result[i] = result[i-1]+i;flag[result[i-1]+i] = true;}}带有详细注释的代码可以在获得Pku acm 1953 World Cup Noise 动态规划题目总结(四)给定一个小于45的整数n,求n位2进制数中不含相邻1的数的个数。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1、0-1背包#include <stdio.h>#include <stdlib.h>//背包问题/*测试数据:输入:8 238 4 5 1 6 6 7 37 8 3 3 4 9 6 2输出:1 0 1 0 1 0 1 1*/int num,c;int v[10];int w[10];int m[10][30];//设m[i][j],则表示在前i个物品中,背包大小是j的情况下,背包所装东西的最大价值void knapsack(){int n=num-1;int jmax,i,j;if(w[n]<c) jmax=w[n];else jmax=c;for(i=0;i<jmax;i++)m[n][i]=0;for(i=w[n];i<=c;i++)m[n][i]=v[n];for(i=n-1;i>0;i--){if(w[i]<c) jmax=w[i];else jmax=c;for(j=0;j<jmax;j++)m[i][j]=m[i+1][j];for(j=w[i];j<=c;j++){if(m[i+1][j]<m[i+1][j-w[i]]+v[i])m[i][j]=m[i+1][j-w[i]]+v[i];elsem[i][j]=m[i+1][j];}}m[0][c]=m[1][c];if(c>=w[0]){if(m[0][c]<m[1][c-w[0]]+v[0])m[0][c]=m[1][c-w[0]]+v[0];}}void trackback(int *x){int n=num-1;int i;for(i=0;i<n;i++){if(m[i][c]==m[i+1][c]) x[i]=0;else{x[i]=1;c=c-w[i];}}if(m[n][c]>0) x[n]=1;else x[n]=0;}int main(){int i,x[10],j;scanf("%d %d",&num,&c);for(i=0;i<num;i++)scanf("%d",&v[i]);for(i=0;i<num;i++)scanf("%d",&w[i]);knapsack();for(i=0;i<=c;i++) printf("%3d",i);printf("\n");for(i=0;i<num;i++){for(j=0;j<=c;j++)printf("%3d",m[i][j]);printf("\n");}trackback(x);for(i=0;i<num;i++)printf("%d ",x[i]);printf("\n");return 0;}2、KMP算法#include<iostream>#include<string.h>using namespace std;inline void BuildNext(const char* pattern, size_t length, unsigned int* next){unsigned int i, t;i = 1;t = 0;next[1] = 0;while(i < length + 1){while(t > 0 && pattern[i - 1] != pattern[t - 1]){t = next[t];}++t;++i;if(pattern[i - 1] == pattern[t - 1]){next[i] = next[t];}else{next[i] = t;}}//pattern末尾的结束符控制,用于寻找目标字符串中的所有匹配结果用while(t > 0 && pattern[i - 1] != pattern[t - 1]){t = next[t];}++t;++i;next[i] = t;}unsigned int KMP(const char* text, size_t text_length, const char* pattern, size_t pattern_length, unsigned int* matches){unsigned int i, j, n;unsigned int next[pattern_length + 2];BuildNext(pattern, pattern_length, next);i = 0;j = 1;n = 0;while(pattern_length + 1 - j <= text_length - i){if(text[i] == pattern[j - 1]){++i;++j;//发现匹配结果,将匹配子串的位置,加入结果if(j == pattern_length + 1){matches[n++] = i - pattern_length;j = next[j];}}else{j = next[j];if(j == 0){++i;++j;}}//返回发现的匹配数return n;}int main(){char a[20],b[20];int n1,n2,n;unsigned int match[100];cin>>a;n1=strlen(a);//待匹配串cin>>b;n2=strlen(b);//模板串n=KMP(a,n1,b,n2,match);cout<<n<<endl;for(int i=0;i<n;i++)cout<<match[i]<<' ';}3、最大子段和#include<iostream>#include<stdio.h>using namespace std;int main(){int T,n;int a[50000];int hd[50000],tl[50000];scanf("%d",&T);while(T--){scanf("%d",&n);int i,temp,max;;for(i = 0;i < n;i++)scanf("%d",&a[i]);//hd[],left -> rightmax = hd[0] = a[0];for(i = 1;i < n;i++){temp = a[i] + hd[i - 1];hd[i] = temp > a[i] ? temp : a[i];}for(i = 1;i < n;i++){hd[i] = max > hd[i] ? max : hd[i];max = hd[i];//tl[],right -> leftmax = tl[n - 1] = a[n - 1];for(i = n - 2;i >= 0;i--){temp = a[i] + tl[i + 1];tl[i] = temp > a[i] ? temp : a[i];}for(i = n - 2;i >= 0;i--){tl[i] = max > tl[i] ? max : tl[i];max = tl[i];}max = hd[0] + tl[1];for(i = 1;i < n - 1;i++){temp = hd[i] + tl[i + 1];max = max > temp ? max : temp;}printf("%d\n",max);}return 0;}4、最长公共子序列(不严格连续)#include <stdio.h>#include <string.h>#define MAXLEN 100void LCSLength(char *x, char *y, int m, int n, int c[][MAXLEN], int b[][MAXLEN]) {int i, j;for(i = 0; i <= m; i++)c[i][0] = 0;for(j = 1; j <= n; j++)c[0][j] = 0;for(i = 1; i<= m; i++){for(j = 1; j <= n; j++){if(x[i-1] == y[j-1]){c[i][j] = c[i-1][j-1] + 1;b[i][j] = 0;}else if(c[i-1][j] >= c[i][j-1]){c[i][j] = c[i-1][j];b[i][j] = 1;}else{c[i][j] = c[i][j-1];b[i][j] = -1;}}}}void PrintLCS(int b[][MAXLEN], char *x, int i, int j) {if(i == 0 || j == 0)return;if(b[i][j] == 0){PrintLCS(b, x, i-1, j-1);printf("%c ", x[i-1]);}else if(b[i][j] == 1)PrintLCS(b, x, i-1, j);elsePrintLCS(b, x, i, j-1);}int main(int argc, char **argv){char x[MAXLEN] = {"ABCBDAB"};char y[MAXLEN] = {"BDCABA"};int b[MAXLEN][MAXLEN];int c[MAXLEN][MAXLEN];int m, n;m = strlen(x);n = strlen(y);LCSLength(x, y, m, n, c, b);PrintLCS(b, x, m, n);return 0;}5、最长公共子序列(不严格连续)#include<iostream>#include<cstdio>#include<memory.h>using namespace std;const int N = 505;int num1[N],num2[N],f[N][N];int main(){int t,n,m;scanf("%d",&t);while(t--){scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&num1[i]);scanf("%d",&m);for(int j=1;j<=m;j++)scanf("%d",&num2[j]);memset(f,0,sizeof(f));int answer=0;int ma;for(int i=1;i<=n;i++){ma=0;for(int j=1;j<=m;j++){f[i][j]=f[i-1][j];if(num1[i]>num2[j]&&f[i-1][j]>ma)ma=f[i-1][j];if(num1[i]==num2[j])f[i][j]=ma+1;}}for(int j=0;j<=m;j++)answer=max(answer,f[n][j]);printf("%d\n",answer);if(t!=0)printf("\n");}return 0;}6、最大子矩阵和#include <iostream>#include<memory.h>using namespace std;//求最大连续子矩阵和,动态规划,O(n^3) of time:/*输入41 -4 3 -8-3 5 2 -32 -1 8 1-1 1 -2 -4输出14*/int max_sum(int n, int *arr){ //求单个序列的最大连续子串和int result=0;int b=0;for(int i=0;i<n;i++){if(b>0) b+=arr[i];else b=arr[i];if(b>result) result=b;}return result;}int max_sum2(int m, int n, int **arr){int result=0;int *b=new int[n];for(int i=0;i<m;i++){memset(b,0,sizeof(int)*n);for(int j=i;j<m;j++){for(int k=0;k<n;k++)b[k]+=arr[j][k];//b[k]=arr[i][k]+arr[i+1][k]+...+arr[j][k]//从例子来说,当i=1,j=2时,有b[k]=arr[1][k]+arr[2][k],这时取到maxint max=max_sum(n,b);if(max>result) result=max;}}delete b;return result;}int main(){int N;cin>>N;int i,j;int **arr=new int*[N];for(i=0;i<N;i++){arr[i]=new int[N];for(j=0;j<N;j++)cin>>arr[i][j];}cout<<max_sum2(N,N,arr)<<endl;for(i=0;i<N;i++)delete arr[i];delete arr;return 0;}7、石子合并问题#include <iostream>#include <stdio.h>using namespace std;//石头合并问题PKU 1086 动态规划/*输入:44 1 2 3输出:*/#define MAX 1000000000int a[202];//每个石头的重量long f[202][202];//f[i][j],第i个石头分到第j个石头合并的最小代价long sum[202][202];//sum[i][j],第i个石头到第j个石头的重量之和void print(int num){int i,j;for(i=1;i<=num;i++){for(j=1;j<=num;j++)printf("%3d",f[i][j]);cout<<endl;}cout<<endl;}void cal(int num){int i,j,k,min,d;for(i=1;i<=num;i++)f[i][i]=0;//不合并时的代价for(i=1;i<num;i++){sum[i][i]=a[i];for(j=i+1;j<=num;j++){sum[i][j]=sum[i][j-1]+a[j];}}sum[num][num]=a[num];for(d=1;d<=num-1;d++){for(i=1;i<=num-d;i++){j=i+d;min=MAX;//i..k为一堆石头,k+1,k+2...j为另一堆石头//f[i][j]为f[i][k]+f[k+1][j]+sum[i][j]的最小值(i<=j<k)for(k=i;k<j;k++)if(min>f[i][k]+f[k+1][j]+sum[i][j]) min=f[i][k]+f[k+1][j]+sum[i][j];f[i][j]=min;print(num);}}}int main(){int num,i;scanf("%d",&num);for(i=1;i<=num;i++)cin>>a[i];cal(num);cout<<f[1][num]<<endl;return 0;}8、最大乘积#include <iostream>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <math.h>using namespace std;//添加乘号得到最大乘积动态规划#define NMAX 12#define CMAX 7__int64 f[NMAX][CMAX];//f[i][j],长度为i,用了j个乘号后的最大值char str[22];void print(int num,int k){ //用于调试时打印f[][]int i,j;for(i=0;i<num;i++){for(j=1;j<=k;j++)printf("%6d",f[i][j]);cout<<endl;}cout<<endl;// system("pause");}int conv(int start,int num){ //在str[i]中,以start为起点,num为长度所表示的数字int sum,i;sum=0;for(i=1;i<=num;i++){sum*=10;sum+=str[start+i-1]-'0';}return sum;}void cal(int num,int chen){int i,j,temp,k;for(i=0;i<num;i++){ //初始化,不用乘号时的情况f[i][0]=conv(0,i+1);}for(j=1;j<=chen;j++){for(i=j;i<num;i++){temp=0;for(k=0;k<i;k++){//a1,a2,a3..an用j个乘号连接//看成是a1,a2...ak已经用j-1个乘号连接,//然后再与后面的ak+1,ak+2..an组成的数用1个乘号连接if(temp<f[k][j-1]*conv(k+1,i-k))temp=f[k][j-1]*conv(k+1,i-k);}f[i][j]=temp;//找到局部的最大乘积}// print(num,chen);}}int main(){int num,chen;//num为字符串长度while(scanf("%d%d",&num,&chen)!=EOF){scanf("%s",&str);cal(num,chen);printf("%I64d\n",f[num-1][chen]);}return 0;}。