网教18. 双塔问题

背景

从前,有一个古老的帝国有两个形状不同的塔分别在不同的两个城市里。这两个塔是用圆形的砖一块一块建成的。这些圆形砖的高度是一样的,其半径都是整数。很明显,尽管这两个塔形状不同,但造塔所使用的圆形砖却有很多是相同的。

过了很多年,一个国王命令他的建筑师们移除两个塔的部分砖以便使它们的形状完全一样,同时使两个塔的高度尽可能的高,并且新塔的砖瓦的排列顺序必须与原来的一样。国王认为这样的两个塔象征着这两个城市之间的和谐和平等,于是命名它们为双胞胎塔。

任务 

现在,两千年以后,你可以来处理这样非常简单的问题:给你两个不同形状塔的描述,你只要算出能建成的新双塔的最多的砖瓦数。

输入

输入包括以下内容:第一行输入两个整数 N1 和 N2 (1 <= N1,N2 <= 100) 分别表示最初时两个塔的砖瓦数;第二行输入 N1 个正整数表示第一个塔砖瓦的半径(按从上到下的顺序排列);下面的一行输入 N2 个整数表示第二个塔砖瓦的半径(按从上到下的顺序排列)。

当输入的 N1 和 N2 为 0 时结束。

输出

输出建成的新双塔的最多的砖瓦数。

来源

UVa: 10066

  测试输入关于“测试输入”的帮助 期待的输出关于“期待的输出”的帮助 时间限制关于“时间限制”的帮助 内存限制关于“内存限制”的帮助 额外进程关于“{$a} 个额外进程”的帮助
测试用例 1 以文本方式显示
  1. 7 6↵
  2. 20 15 10 15 25 20 15↵
  3. 15 25 10 20 15 20↵
  4. 8 9↵
  5. 10 20 20 10 20 10 20 10↵
  6. 20 10 20 10 10 20 10 10 20↵
  7. 0 0↵
以文本方式显示
  1. Twin Towers #1↵
  2. Number of Tiles : 4↵
  3. Twin Towers #2↵
  4. Number of Tiles : 6↵
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]。

用图来表示:
flow

状态转移方程:
recursive formula
有了这个公式,直接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;  
}  



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值