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;}



 

原创粉丝点击