Chinaunix首页 | 论坛 | 博客
  • 博客访问: 624795
  • 博文数量: 79
  • 博客积分: 848
  • 博客等级: 军士长
  • 技术积分: 1800
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-26 19:30
文章分类

全部博文(79)

文章存档

2015年(4)

2013年(39)

2012年(36)

分类: C/C++

2013-06-27 15:44:59

上周六参加了一场微软秋令营的笔试,感觉最后一道笔试题出的蛮有水平。
题目如下:
给定一个数字的序列,例如:1、2、3、4、5、6、7,序列中随意的添加“+"或者”-“,使得最后的运算结果,跟给定的数值,例如:9,之间的差值最小。请给出符合要求的结果串,例如:1 + 3 + 4 + 5 + 6 - 7 - 2
拿到这道题目,本人的第一反应就是对于给定的序列做和然后减去目标数值之后除以2获得一个数值x,然后再去原来的序列中查找和为x的序列,就是应该减去的序列。但是困难就又出现我们如何在一个序列中找出和为x的所有序列呢?
这个很容易让我联想到一个经典的动态规划问题,背包问题:
有N件物品和一个容量为V的背包。第i件物品的重量是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。
这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。
用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其便是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}。可以压缩空间,f[v]=max{f[v],f[v-c[i]]+w[i]}
这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。所以有必要将它详细解释一下:“将前i件 物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品, 那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容 量为v-c[i]的背包中”,此时能获得的最大价值就是f [i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。

在这里我们要得到和最接近x的目标元素的序列,实际上就可以当作是容量为x的大小的一个背包,我们有质量不等n个元素,将其中m个元素放入包,使得他们的和不超过x,并且达到最大值。
下面是我的解法:

点击(此处)折叠或打开

  1. /*************************************************************************
  2.     > File Name: test87.cpp
  3.     > Author: dongdaoxiang
  4.     > Func: Find Min Gap
  5.     > Mail: dongdaoxiang@ncic.ac.cn
  6.     > Created Time: 2013年06月26日 星期三 21时54分13秒
  7.  ************************************************************************/
  8. #include<iostream>
  9. #include<string>
  10. #include<algorithm>
  11. #include<sstream>
  12. #include<vector>
  13. using namespace std;

  14. void init(int *a, int m, int n)
  15. {
  16.     int i = 0;
  17.     for(i = 0; i < m*n; i++)
  18.     {
  19.         a[i] = 0;
  20.     }
  21. }

  22. inline string IntToString(int a) //整形到字符串的转换
  23. {
  24.     string dest;
  25.     stringstream ss;
  26.     ss << a;
  27.     ss >> dest;
  28.     return dest;
  29. }

  30. inline int Max(const int a, const int b)
  31. {
  32.     return a > b ? a : b;
  33. }

  34. int OptResult(const vector<int> &arr, const int dest, int index) //背包问题,获取辅助数组元素值函数
  35. {
  36.     if(index < 0)
  37.     {
  38.         return 0;
  39.     }
  40.     if(index == 0)
  41.     {
  42.         if(arr[index] <= dest)
  43.             return arr[index];
  44.         else
  45.             return 0;
  46.     }
  47.     if(arr[index] > dest)
  48.     {
  49.         return OptResult(arr, dest, index - 1);
  50.     }
  51.     else
  52.     {
  53.         return Max(OptResult(arr, dest - arr[index], index - 1) + arr[index], OptResult(arr, dest, index - 1));
  54.     }
  55. }

  56. void Find(vector<int> &minus, vector<int> &arr, int *a, int index, int wight, int size) //回溯找到最优解
  57. {
  58.     if(a[size * index + wight] == 0)
  59.         return;
  60.     if(a[size * index + wight] < arr[index])
  61.         Find(minus, arr, a, index - 1, wight, size);
  62.     else
  63.     {
  64.         if(a[size * index + wight] - arr[index] == 0)
  65.         {
  66.             minus.push_back(arr[index]);
  67.             arr[index] = -1;
  68.             return;
  69.         }
  70.         if(a[size * index + wight] - arr[index] == a[(index - 1)*size + wight - arr[index]])
  71.         {
  72.             minus.push_back(arr[index]);
  73.             int temp = arr[index];
  74.             arr[index] = -1;
  75.             Find(minus, arr, a, index - 1, wight - temp, size);
  76.         }
  77.         else if(a[index * size + wight] == a[(index - 1) * size + wight])
  78.         {
  79.             Find(minus,arr,a,index - 1, wight, size);
  80.         }
  81.     }
  82. }


  83. void Bag(vector<int> &arr, const int dest, vector<int> &minus)
  84. {
  85.     int m = arr.size();
  86.     int n = dest;
  87.     int c[m * (n + 1)];
  88.     init(c, m, n + 1);
  89.     int i = 0;
  90.     int j = 0;
  91.     for(i = 0; i < arr.size(); i++)
  92.     {
  93.         for(j = 0; j <= dest; j++)
  94.         {
  95.             c[i * (dest + 1) + j ] = OptResult(arr, j, i);
  96.             cout << c[i * (dest+ 1) + j] << " ";
  97.         }
  98.         cout << endl;
  99.     }
  100.     cout << "dest: " << dest << endl;
  101.     Find(minus, arr, c, arr.size() - 1, dest, n + 1);
  102. }


  103. void MiniGap(vector<int> &ivec, const int dest, string &result)
  104. {
  105.     if(ivec.empty())
  106.     {
  107.         return;
  108.     }

  109.     if(ivec.size() == 1)
  110.     {
  111.         result = IntToString(ivec[0]);
  112.     }

  113.     size_t i = 0;
  114.     int sum = 0;
  115.     vector<int> minus;
  116.     for(i = 0; i != ivec.size(); i++)
  117.     {
  118.         sum += ivec[i];
  119.     }
  120.     sort(ivec.begin(), ivec.end());
  121.     int temp = (sum - dest + 1) >> 1;
  122.     if(temp < 0)
  123.     {
  124.         return;
  125.     }
  126.     else
  127.     {
  128.         Bag(ivec, temp, minus);
  129.     }
  130.     for(i = 0; i != minus.size(); i++)
  131.     {
  132.         result += '-';
  133.         result += IntToString(minus[i]);
  134.     }
  135. }

  136. int main()
  137. {
  138.     vector<int> ivec;//给定的元素序列
  139.     int i = 0;
  140.     int dest = -27; //目标元素的数值
  141.     string result;
  142.     string result2;//结果串
  143.     for( i = 1; i <= 8; i++)
  144.     {
  145.         ivec.push_back(i + 6);
  146.     }
  147.     MiniGap(ivec, dest, result);
  148.     for(i = 0; i < 8; i++)
  149.     {
  150.         if(ivec[i] != -1)
  151.         {
  152.             result2 += IntToString(ivec[i]);
  153.             result2 += '+';
  154.         }
  155.     }
  156.     string::iterator it = result2.end() - 1;
  157.     result2.erase(it);
  158.     result2 += result;
  159.     cout << result2 << endl;
  160.     return 0;
  161. }
可以得到如下的结果:

点击(此处)折叠或打开

  1. 8+9+11-14-13-12-10-7




阅读(2693) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~