数塔问题
观察下面的数字金字塔。写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。
在上面的样例中,从7→3→8→7→5 的路径最大
状态转移方程: f[i][j] = max(f[i + 1][j],f[i + 1][j + 1]) + a[i][j];【i从n->1进行更新】
i>n时,f[i][j]=0;i=n 时 f[i][j]=a[i][j];
想象成填表,从最后一行开始,自底向上,每一行自左向右;
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010;
int a[N][N];//存储数塔
int f[N][N];//表示从第i行第j列到第n行的最大路径
int n;
int main()
{
while (cin >> n)
{
for (int i = 1;i <= n;i++)
for (int j = 1;j <= i;j++)
cin >> a[i][j];
for (int i = n;i >= 1;i--)//用i来表示行,且从最后一行开始
for (int j = 1;j <= i;j++)//每行有i列,且从第一列开始
f[i][j] = max(f[i + 1][j],f[i + 1][j + 1]) + a[i][j];//自底向上计算最长路径
cout << f[1][1] << endl;//当for循环结束完毕之后f[1][1]:从数塔第1行第1列开始的最长路径
}
return 0;
}
TSP旅行商问题
一个售货员必须访问n个城市,恰好访问每个城市一次,并最终回到出发城市。
售货员从城市i到城市j的旅行费用是一个整数,旅行所需的全部费用是他旅行经过的的各边费用之和,而售货员希望使整个旅行费用最低。
状态转移方程:
依旧是填表, 用索引的二进制的每一位表示是否走过城市
void Tsp_getShoretstDistance()
{
int i,j,k;
//初始化第一列
for(i=0;i<city_number;i++)
{
process[i][0]=distance[i][0];//V为空集的情况
}
//初始化剩余列
for(j=1;j<(1<<(city_number-1));j++)//对每一个 i, V集合有 1<<(city_number-1)种可能
{
for(i=0;i<city_number;i++)
{
process[i][j]=0x7ffff;//process是从i开始,经过由“j”确定的集合,回到0点走的距离
//对于数字x,通过判断布尔表达式 (((x >> (i - 1) ) & 1) == 1的真值来实现要看它的第i位是不是1,第i位为1表示第i个城市在V集合中
if(((j>>(i-1))&1)==1)
{
continue;//第i个城市在V集合中
}
for(k=1;k<city_number;k++)//遍历集合V的元素,寻找从i经过V的最短距离
{
if(((j>>(k-1))&1)==0)
{
continue;//第k个城市不在V集合中
}
if(process[i][j]>distance[i][k]+process[k][j ^ (1 << (k - 1))])
{
process[i][j]=distance[i][k]+process[k][j ^ (1 << (k - 1))];
//i走向V中的K点,K走向V中剩余元素
}
}
}
}
cout<<"最短路径长度:";
cout<<"sum="<<process[0][(1<<(city_number-1))-1]<<endl;
}
零钱兑换
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 0 。你可以认为每种硬币的数量是无限的。
算法设计思路:
设F(n)是总金额为n的最少硬币数
n>0时,F(n)=min{F(n-dj)}+1 (n>=dj)
n=0时,F(0)=0;
int changeMaking(int D[],int m,int n) //m为D的len,n为金额
{ int i;
F[0]=0;
for(i=1;i<=n;i++) //从1 到n的各个值所需的币数
{
int temp=10000,j=1;
while(j<=m and i>=D[j])
{ temp=min(F[i-D[j]],temp);
j=j+1;
}
F[i]=temp+1;
}
return F[n];
}