JOJ 2171 2488 1868 2237

 

这几天专门挑些简单的算法题目做做,怕忘记,贴在这里。
JOJ 2171 An Easy Problem: http://acm.jlu.edu.cn/joj/showproblem.php?pid=2171
给定一个正整数 N N 不超过 40 ,问在 N 位由数字 0 1 组成的所有串中,没有连续 3 1 出现的串的个数是多少。比如 N 1 的时候,有 0 1 两个, N 2 的时候,有 00 01 10 11 四个, N 3 的时候, 111 就不合法了,此时这样串有 7 个。
解法:动态规划。所有的串都能按照最末两位分成四组。假设在 n 位合法的 0 1 串中,以 00 结尾的串的个数为 f0(n) ,以 01 结尾的串个数为 f1(n) ,以 10 结尾的串个数为 f2(n) ,以 11 结尾的串个数为 f3(n) ,则 n 位合法的 0 1 串的总数 f(n)=f0(n)+f1(n)+f2(n)+f3(n) 。当串的长度扩展到 n+1 位时,我们看这它们各自的个数如何动态变化。从 n 位到 n+1 位,只需要在 n 位串的末尾追加一位 0 或一位 1 即可。对四个函数分类讨论:
00 结尾:加 0 后变成以 00 结尾,加 1 后变成 01 结尾;
01 结尾:加 0 后变成以 10 结尾,加 1 后变成 11 结尾;
10 结尾:加 0 后变成以 00 结尾,加 1 后变成 01 结尾;
11 结尾:加 0 后变成以 10 结尾,加 1 后不合法。
所以,有:  f0(n+1) = f0(n) + f2(n),    f1(n+1) = f0(n) + f2(n),  f2(n+1) = f1(n) + f3(n),   f3(n+1) = f1(n)
n 2 时,有 f0(2) = f1(2) = f2(2) = f3(2) = 1 。这样,经过递推可以很快计算出结果。中间要考虑溢出的情况。当 n = 37 时,结果超过了 70 亿,必须用 double 类型。
 
JOJ 2488 Function Value: http://acm.jlu.edu.cn/joj/showproblem.php?pid=2488
函数 f(n) 如下定义:当 n=1 时, f(n) = 1 ;当 n 是一个素数时, f(n) = f(n – 1) ;否则, f(n) = f(k) + 1 ,其中 k n 除自身以外最大的因子。输入数据 n 为不超过 2 31 次方的正整数。
这个题目直接按题意来做即可。因为 n 是素数时 n-1 ,这就变成了合数,然后再除以 k k 至少是 2 ,所以 n 最起码被砍到了一半。所以这个题目的计算量就是 O(log(n)) 的。代码如下:
#include <stdio.h>
 
int main() {
    unsigned int n, ans, k;
    while ( scanf ( "%u" , &n) != EOF) {
       ans = 0;
       while (1) {
           if (n == 1 || n == 2) { ans++; break ; }
           for (k = 2; k * k <= n; k++)
              if (n % k == 0) break ;
           if (n % k) n--;
           else { n /= k; ans++; }
       }
       printf ( "%u/n" , ans);
    }
    return 0;
}
 
JOJ 1868 Blocks: http://acm.jlu.edu.cn/joj/showproblem.php?pid=1868
N 个长宽高都为 1 的小立方体,把它们砌成一个长方体或正方体,能得到的最小的表面积是多少。输入数据 N 为不超过 1000 的正整数。
设长宽高分别为 L,W,H ,题目要求就是 L*W*H=N 的情况下, 2*(L*W + L*H + W*H) 的最小值是多少。其中 L,W,H 都是自然数。不需要用数学来分析函数的极值。直接搜索即可。当 L 确定的情况下,问题变成了 W*H = N / L 为常数,求 W+H+W*H 的最小值的问题。枚举 W 即可确定 H 。代码如下:
#include <stdio.h>
 
int l, w, h;
 
void solve( int m) {
    int t = 2147483647, tw;
    for (w = 1; w <= m / 2 + 1; w++) {
       if (m % w == 0) {
           h = m / w;
           if (w + h + w*h < t) {
              t = w+h+w*h;
              tw = w;
           }
       }
    }
    w = tw;
    h = m / w;
}
 
int main() {
    int c, n, ans, t;
    scanf ( "%d" , &c);
    while (c--) {
       scanf ( "%d" , &n);
       ans = 2147483647;
       for (l = 1; l <= n/2 + 1; l++) {
           if (n % l == 0) {
              solve(n/l);
              t = 2 * (l*w + l*h + w*h);
              if (t < ans) ans = t;
           }
       }
       printf ( "%d/n" , ans);
    }
    return 0;
}
 
JOJ 2237 Hero Ranklist: http://acm.jlu.edu.cn/joj/showproblem.php?pid=2237
Arthur 想要将手下的战士按照能力进行排名 , 选择出得力的助手进行冒险 . 他收集了很多人之间比武的胜负情况,如 A 战胜了 B B 战胜了 C 等。他发现,这些胜负关系之间彼此互不矛盾,也就是不能出现 C 又战胜了 A 这种情况,但很多人之间并没有比武 , 也就无法衡量谁更强。 在这种情况下, Arthur 想把所有可能的排行榜都列举出来,供他进一步研究。
本题目包括多个 Case 。每个 Case 的第一行有 2 个数字 m,n. m<13 ,代表有多少个人物,每个人物使用一个大写字母表示。之后有 n , n<100, 每一行有 2 个字母 X Y, 中间有一个减号 , 表示 X 战胜过 Y 。可以假定输入没有重复 .
这个题目就是拓扑排序,下面是用回溯写的拓扑排序代码:
void tsort( int step) {
    int i, j;
 
    if (step >= m) {
       ans[step] = 0;
       printf ( "%s/n" , ans);
       return ;
    }
 
    for (i = 0; i < m; i++) {
       if (in[i] == 0 && !visited[i]) {
           visited[i] = 1;
 
           for (j = 1; j <= Matrix[i][0]; j++) {         
              in[Matrix[i][j]]--;
           }
          
           ans[step] = 'A' + i;
           tsort(step + 1);
 
            for (j = 1; j <= Matrix[i][0]; j++) {
                in[Matrix[i][j]]++;
            }
           visited[i] = 0;
       }
    }
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值