1+1到底2不2?
来源:互联网 发布:2017年大学招生数据 编辑:程序博客网 时间:2024/04/30 01:30
整体趋于无穷大,部分趋于无穷小。按照“无有即无穷,无穷即无有”的哲学(参考《算法之道》),因此其于0无差别,也证明是可以相互转化的,在转化过程中,我们要找到“守恒”条件,处理好细节问题,实现整体。归纳之整体到部分的分析过程,再到部分到整体的实现过程。
下面:动态规划和图搜索(1)动态规划
将待求解问题分解成若干子问题;
最优子结构:最优策略的子策略也是最优策略(不互相独立)
重叠子问题:每次产生的子问题并不总是新问题
从子问题的解得到原问题的解。
例1:费用问题
为一个乘游船去某个景点的游客计算最少租船策略。
输入:测试数据第一行n表示起点站0到后面站的路径数,接下来是初始点0到n个站得代价,再下来的是第一个站点到剩余n-1个站点的租金,依此类推。
例如输入
3
2 3 6
1 3
2
3
4 7 9
4 5
6
输出
Case1 :5
Case2:9
/************************************************************************//* 设m[i]起点站到第i站得最少游船租金/* 第k站中转到第i站/* 状态转移方程 m[i] = min{m[k] + r[k][i]} /* @Bean/************************************************************************/#include <iostream>using namespace std;const int MAXNUM = 256;int n, r[MAXNUM][MAXNUM], m[MAXNUM];void money(int rr[][MAXNUM], int mm[], int nn){ for (int i = 1; i <= nn; i++) { m[i] = r[0][i]; for (int j = i - 1; j > 0; j --) { if (m[i] > m[j] + rr[j][i]) { m[i] = m[j] + rr[j][i]; } } }}int main(){ int num = 0, a; while (cin >> n) { if (n == 0) { break; } else { num ++; for (int i = 0; i < n; i++) { for (int j = i + 1; j <= n; j++) { cin >> a; r[i][j] = a; } } money(r, m, n); cout << "Case" << num << ":" << endl; cout << m[n] << endl; } } system("pause"); return 0;}
例2:有一个数字串312,有两种分法,3*12 = 36和31*2=62得的乘数最大
输入:
第一行2个自然数N,K(6<=N<=40, 1<=K<=6 )
第二行是长度N的数字串
/************************************************************************//* F[i][k]是长度i+1插入k个×/* 状态转移方程 F[i][k] = max{F[t][k-1]*num[t+1][i]} /* @Bean/************************************************************************/#include <iostream>#include <cstring>using namespace std;int const k_max_num = 41;int num[k_max_num], len;// num[t...n] 整数合成long nn(int t, int z){ int i; long a = num[t]; for (i = t + 1; i <= z; i++) { a = a * 10 + num[i]; } return a;}int main(){ int i, N, c, k, t; long n, F[k_max_num][k_max_num]; char s[k_max_num]; // c 即题目的 K while (cin >> N >> c) { cin >> s; len = strlen(s); for (i = 0; i < len; i++) { num[i] = s[i] - 48; // 字符串转换为整型 } k = 0; F[0][0] = num[0]; // num[0...i]整数合成 for (i = 1; i < len; i++) { F[i][0] = F[i-1][0] * 10 + num[i]; } k = 1; // 划分c+1个数字 for (k = 1; k <= c; k++) { for(i = k; i < len; i++) { long a = -1; for (t = k - 1; t < i; t++) { n = nn(t+1, i); // (多位数)整数乘法 long b = F[t][k-1] * n; if (a < b) a = b; } F[i][k] = a; } } cout << F[len -1][c] << endl; } return 0;}
(2) A*算法void AStar() // 最小值
{
CLOSED与OPEN初始化为空;
将起始节点放入OPEN表;
while(open!=NULL)
{
从OPEN表中取估价值f最小的节点CurrentNode;
将CurrentNode节点从OPEN表中删除;
if(CurrentNode节点==目标节点)
{
求得路径PATH;break;
}else
{
for (CurrentNode节点的每一个子节点NewNode)
{
if(NewNode不在OPEN表和CLOSED表中)
{
求NewNode的估价值f;
将NewNode插入OPEN表中;
}else if (NewNode在OPEN表中)
{
if(NewNode的估价值f小于OPEN表中节点的估价值)
更新OPEN表中的估价值; // 取最小路径的估价值
}else // NewNode在CLOSED表中
{
if (NewNode的估价值f小于CLOSED表中节点估价值)
{
更新CLOSED表中的估价值;
从CLOSED表中移除节点,并把NewNode放入OPEN表;
}
}
将CurrentNode节点插入CLOSED表中;
按照估价值将OPEN表中的节点排序;
}
}
}
}
八数码问题:
#include <iostream>#include <vector>using namespace std;int dist[9][9];typedef struct s_node{ struct s_node *father; struct s_node *prev; struct s_node *next; int step; // 已有步数 int diff; // 节点估计函数值 int weight; // 节点的估价函数值weight = step = diff int m[9]; // m[i]的取值0-8,0表示空格}node;void init() // 初始化,计算哈密顿距离列表{ int i, j, posi[9][2], dist[9][9]; posi[0][0] = 2; posi[0][1] = 2; for (i = 1; i < 9; ++i) { posi[i][0] = (i-1)/3; posi[i][1] = (i-1)%3; } for (j = 0; j < 9; ++j) { for (i = 0; i < 9; ++i) { dist[j][i] = abs(posi[i][0] - posi[j][0]) + abs(posi[i][1] - posi[j][1]); } }}node* open_out(node *head) // 取头结点出列{ node *p; if (head->next == NULL) { return NULL; } p = head->next; head->next = p->next; if (p->next != NULL) { p->next->prev = head; } p->prev = NULL; p->next = NULL; return p;}int open_insert(node *head, node *item){ node *p, *q; p = head->next; q = head; while (p != NULL && item->weight > p->weight) { q = p; p = p->next; } q->next = item; item->prev = q; item->next = p; if (p!=NULL) { p->prev = item; } return 0;}int close_insert(node *head, node *item) //将item插入close的头部{ item->next = head->next; item->prev = head; head->next = item; if (item->next != NULL) { item->next->prev = item; } return 0;}int inv_pair(int m[]) // 计算八数码棋盘的逆序对数{ int i, j, total = 0; for (i = 1; i < 9; ++i) { for (j = 0; j < i; ++j) { if (m[i] != 0 && m[j] != 0 && m[j] < m[i]) { ++total; } } } return total;}void swap(int *a, int *b) // 棋盘符交换{ int c; c = *a; *a = *b; *b = c;}int operate(int m[], int op){ int black = 0; while (m[black] != 0 && black < 9) { ++black; } if (black == 9) { return 1; } switch (op) { case 1:// 上 if (black > 2) { // 不在第一行 swap(m + black, m + black -3); } break; case 2: // 下 if (black < 6) { // 不在第三行 swap(m + black, m + black + 3); } break; case 3: // 左 if (black != 0 && black != 3 && black != 6) { // 不在第一列 swap(m + black, m + black -1); } break; case 4: // 右 if (black != 2 && black != 5 && black != 8) { swap(m + black, m + black + 1); } break; default: return 1; } return 0;} int diff(int m[], int n[]) // 采用不同位置的个数进行估值--估值方法一 { int i, d = 0; for (i = 0; i < 9; i++) { if (m[i] != n[i]) { ++d; } } return d; } int eval(int m[]) // 对0-8数码进行Hamilton距离进行估值--估值方法二 { int i, val = 0; for (i = 0; i < 9; i++) { val += dist[i][m[i]]; } return val; }void input_m(int m[]) // 初始八数码棋盘输入{ char str[10]; cin.getline(str, 10); for (int i = 0; i < 9; i++) { m[i] = str[i] - 48; }}// 检查棋盘m在OPEN和CLOSED中是否出现,如找到返回1,否则返回0int new_m(node *open, node *close, int m[]){ node *p; int same, i; p = close->next; while (p != NULL) // 先在closed中查找 { same = 1; for (i = 0; i < 9; ++i) { if (p->m[i] != m[i]) { same = 0; } } if (same) return 0; p = p->next; } p = open->next; while (p != NULL) { same = 1; for (i = 0; i < 9; ++i) { if (p->m[i] != m[i]) { same = 0; }// if (same) return 0; } if (same) return 0; p = p->next; } return 1;}// 拷贝节点node* copy_node(node *origin){ node *p; int i; p = new node; p->step = origin->step; p->diff = origin->diff; p->weight = origin->weight; for (i = 0; i < 9; ++i) (p->m)[i] = (origin->m)[i]; return p;}// 从后向前计算移动步数int print_result(node *item){ node *p; int step; p = item; if (p != NULL) { step = print_result(p->father); return step + 1; } else return -1;}// 删除链表void free_queue(node *head){ node *p, *q; p = head->next; while (p != NULL) { q = p->next; delete p; p = q; } delete head;}int main(){ node *open, *closed; node *p1, *p2; int op, node_num, total_step, n, i; int final_m[9] = {1, 2, 3, 4, 5, 6, 7, 8, 0}; // 目标状态 bool flg; init(); cin >> n; cin.get(); for (i = 0; i < n; i++) { cout << "Case" << i + 1 << ":" << endl; flg = false; open = new node; closed = new node; open->prev = closed->prev = open->next = closed->next = NULL; p1 = new node; p1->father = NULL; p1->step = 0; input_m(p1->m); if (diff(p1->m, final_m) == 0) //如果初始棋盘就是目标棋盘 { cout << 0 << endl; continue; } else { open_insert(open, p1); // 将初始棋盘信息存入open中 if ((inv_pair(p1->m)%2) != (inv_pair(final_m)%2)) // 检查是否有解 { cout << "Impossible!\n"; continue; } node_num = 1; p1 = open_out(open); // 从open表中取出节点 while (p1 != NULL) { close_insert(closed, p1); // 将节点存入closed中 // generate new node // 对当前棋盘进行上下左右尝试 for (op = 1; op <= 4; ++op) { p2 = copy_node(p1); operate(p2->m, op); // 得到新棋盘状态p2 // 检查p2是否在open或closed表中出现 if (new_m(open, closed, p2->m)) { p2->father = p1; p2->step = p1->step + 1; p2->diff = eval(p2->m); // 求新节点的启发函数值 p2->weight = p2->step + p2->diff; // 求新节点估价函数值 if (diff(p2->m, final_m) == 0) // 找到解 { total_step = print_result(p2); // 计算移动步数 cout << total_step << "\n"; free_queue(open); free_queue(closed); flg = true; break; } else { // 如p2不是目标状态,插入open表 open_insert(open, p2); } } else delete p2; } if (flg) break; p1 = open_out(open); } } } system("pause"); return 0;}
- 1+1到底2不2?
- 解决tableView滑不到底
- 代购到底赚不赚钱
- 1M到底等于多少
- 1英寸CMOS到底多大?
- AD分辨率到底是1/(2^n-1), 还是1/2^n
- 关于Struts,到底是要先学了1再学2,还是直接学2?
- SQA到底应该做一些什么1---培训的故事2
- EXT到底收不收费啊!
- 到底第一时间接电话应该不应该?
- 计算机专业到底应不应该读研?
- 我不知道这样到底对不对
- 虚拟运营商到底给不给力?
- 其实你不知道MultiDex到底有多坑
- 其实你不知道MultiDex到底有多坑
- 到底应不应该上培训班
- 其实你不知道MultiDex到底有多坑
- 其实你不知道MultiDex到底有多坑
- (45)21.4.3 并发 练习 19---Java编程思想之并发笔记
- (46)21.4.3 并发 练习 20---Java编程思想之并发笔记
- 抽象工厂模式
- 网站布局剖析实例:网页黄金分割
- (47)21.4.3 中断2---Java编程思想之并发笔记
- 1+1到底2不2?
- (48)21.4.4 检查中断---Java编程思想之并发笔记
- javascript的闭包
- Linux源的知识。。。
- Eclipse 4.2.0 安装及汉化全过程
- 面向对象和基于对象
- 软件质量管理之困境与对策思考
- 让archlinux bash语法高亮
- Notepad++的字体设置加Consolas和微软雅黑混合字体<转载>