背景
从前,有一个古老的帝国有两个形状不同的塔分别在不同的两个城市里。这两个塔是用圆形的砖一块一块建成的。这些圆形砖的高度是一样的,其半径都是整数。很明显,尽管这两个塔形状不同,但造塔所使用的圆形砖却有很多是相同的。
过了很多年,一个国王命令他的建筑师们移除两个塔的部分砖以便使它们的形状完全一样,同时使两个塔的高度尽可能的高,并且新塔的砖瓦的排列顺序必须与原来的一样。国王认为这样的两个塔象征着这两个城市之间的和谐和平等,于是命名它们为双胞胎塔。
任务
现在,两千年以后,你可以来处理这样非常简单的问题:给你两个不同形状塔的描述,你只要算出能建成的新双塔的最多的砖瓦数。
输入
输入包括以下内容:第一行输入两个整数 N1 和 N2 (1 <= N1,N2 <= 100) 分别表示最初时两个塔的砖瓦数;第二行输入 N1 个正整数表示第一个塔砖瓦的半径(按从上到下的顺序排列);下面的一行输入 N2 个整数表示第二个塔砖瓦的半径(按从上到下的顺序排列)。
当输入的 N1 和 N2 为 0 时结束。
输出
输出建成的新双塔的最多的砖瓦数。
来源
UVa: 10066
测试输入 | 期待的输出 | 时间限制 | 内存限制 | 额外进程 | |
---|---|---|---|---|---|
测试用例 1 | 以文本方式显示
| 以文本方式显示
| 1秒 | 1024KB | 0 |
大名鼎鼎的最长公共子序列问题。使用dp求解。
引进一个二维数组c[][],用c[i][j]记录X[i]与Y[j] 的LCS 的长度,b[i][j]记录c[i][j]是通过哪一个子问题的值求得的,以决定搜索的方向。
我们是自底向上进行递推计算,那么在计算c[i,j]之前,c[i-1][j-1],c[i-1][j]与c[i][j-1]均已计算出来。此时我们根据X[i] = Y[j]还是X[i] != Y[j],就可以计算出c[i][j]。
我们是自底向上进行递推计算,那么在计算c[i,j]之前,c[i-1][j-1],c[i-1][j]与c[i][j-1]均已计算出来。此时我们根据X[i] = Y[j]还是X[i] != Y[j],就可以计算出c[i][j]。
用图来表示:
状态转移方程:
有了这个公式,直接dp就行了。
AC代码:
#include<stdio.h>
#include<string.h>
int a[102], b[102], dp[102][102];
int max(int a, int b)
{
return a > b ? a : b;
}
int main()
{
int n1, n2, index = 0;
while (1)
{
index++;
scanf("%d%d", &n1, &n2);
if (n1 == 0 && n2 == 0)
break;
int i;
for (i = 1; i <= n1; i++)
scanf("%d", &a[i]);
for (i = 1; i <= n2; i++)
scanf("%d", &b[i]);
memset(dp, 0, sizeof(dp));
dp[0][0] = 0;
int j;
for (i = 1; i <= n1;i++)
for (j = 1; j <= n2;j++)
if (a[i] == b[j])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
printf("Twin Towers #%d\nNumber of Tiles : %d\n", index, dp[n1][n2]);
}
return 0;
}