JOJ 2171 2488 1868 2237

来源:互联网 发布:mango db mac 编辑:程序博客网 时间:2024/05/17 05:35

 

这几天专门挑些简单的算法题目做做,怕忘记,贴在这里。
JOJ 2171 An Easy Problem: http://acm.jlu.edu.cn/joj/showproblem.php?pid=2171
给定一个正整数NN不超过40,问在N位由数字01组成的所有串中,没有连续31出现的串的个数是多少。比如N1的时候,有01两个,N2的时候,有00011011四个,N3的时候,111就不合法了,此时这样串有7个。
解法:动态规划。所有的串都能按照最末两位分成四组。假设在n位合法的01串中,以00结尾的串的个数为f0(n),以01结尾的串个数为f1(n),以10结尾的串个数为f2(n),以11结尾的串个数为f3(n),则n位合法的01串的总数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)
n2时,有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,其中kn除自身以外最大的因子。输入数据n为不超过231次方的正整数。
这个题目直接按题意来做即可。因为n是素数时n-1,这就变成了合数,然后再除以kk至少是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战胜了BB战胜了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;
       }
    }
}
 
原创粉丝点击