最佳队形(动态规划)

问题描述:

      要参加某项比赛,参赛人员需要排成两队(分别定义为A和B,每队人数至少为1且每队人数随意)。每人写一个字母代表自己,字母为a-z或A-Z。例如A对的字母为:c m c,B对字母为:s n m n。

     最佳队形为:

1. 每个人前后可有任意个空位,也可以没有空位;

2. 两队在添加空位后长度必需一致。

3. 根据每个人所写的字母,定义A对于B队的距离为相应位置上的字母的距离总和;

4. 两队相应位置的距离定义为:

      1)两个非空位的距离定义为它们所对应字母的ASCII码的差的绝对值;

      2)空位与其他任意非空位之间的距离为已知的定值K;

      3)空位与空位的距离为0.

5. 最佳队形为:在A,B的所有可能的队形中,必定存在等长的队A1,B1,使得A1和B1的距离最小。那么这个队形就是最佳队形。


问题分析:

      算法设计中常用的算法思想是枚举,回溯,分治,贪心,动归。显然此题用动归较易解决。动归的关键是定义子问题以及子问题之间的关系,当然,也需要找出最小子问题即能够直接求解出的问题。

我们定义如下子问题形式:

     dp(i,j)表示A(1,i)和B(1,j)的最佳队形的长度。那么,问题就是求解出dp(len(A),len(B))。

动归关系式:

     dp(i,j) =  min {  dp(i-1,j)+K, dp(i,j-1)+K, dp(i-1,j-1) + abs(A(i)-B(j))   }

最小子问题:

    A(1,i)或B(1,j)与空格之间的距离。

代码实现:

#include <iostream>
#include <vector>
#include <string>
using namespace std;

int GetBestQueue(string& A, string& B,int K)
{
        int Alength = A.length();
        int Blength = B.length();
        vector<vector<int> > dp(Alength + 1,vector<int>(Blength+1));
       // Initial the array dp
	for (int i = 1; i <= Alength; i++)
		dp[i][0] = i*K;
	for (int i = 1; i <= Blength; i++)
		dp[0][i] = i*K;
	dp[0][0] = 0;
       //Solution
	for (int i = 1; i <= B.length(); i++)
	{
		for (int j = 1; j <= A.length(); j++)
		{
			if (dp[j - 1][i] < dp[j][i - 1])
				dp[j][i] = dp[j - 1][i] + K;
			else
				dp[j][i] = dp[j][i - 1] + K;
                        int tem = abs(A[j - 1] - B[i - 1]);

			if (dp[j][i] > dp[j - 1][i - 1] + tem)
				dp[j][i] = dp[j - 1][i - 1] + tem;
		}
	}
	return dp[Alength][Blength];
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值