2009年12月16日

TopCoder SRM 403 Level2 1000
4和7是幸运数字,如果一个数只包含4和7,那么这个数字也是一个幸运数字
给定一个1-1,000,000的数字,求这个数字是否可以仅由幸运数字相加得出,返回所有的幸运数字加数,如果有多组解,返回加数最少的一组

以前没有遇到过这样的DP题目
这题加深了我对于“每个子问题的答案都是最佳答案”的理解
首先是额外的计算
将范围以内的幸运数字打表
然后从输入数字N开始递减DP计算
N的步数为0
如果最后0的步数为正数
说明有解
再从0开始递增寻找解的路径

不过这个方法最后也没有通过tc的系统测试
数字一大就超时了
后面又时间再研究一下
看看有没有办法在改进

 1 import java.util.*;
 2 import java.util.regex.*;
 3 import java.text.*;
 4 import java.math.*;
 5 import java.awt.geom.*;
 6 
 7 public class TheSumOfLuckyNumbers
 8 {
 9     
10     public int[] sum(int n)
11     {
12         ArrayList<Integer> table = calTable();
13         int[] dp = new int[n+1];
14         Arrays.fill(dp, Integer.MAX_VALUE-10);
15         dp[n] = 0;
16         int i , j;
17         for(i = n; i > 0 ; -- i){
18             for(int lucky:table){
19                 if(i - lucky >=0 && dp[i] + 1 < dp[i - lucky])
20                     dp[i - lucky] = dp[i] + 1;
21             }
22         }
23         if(dp[0== Integer.MAX_VALUE)
24             return new int[0];
25         ArrayList<Integer> ans = new ArrayList<Integer>();
26         int total = dp[0]-1;
27         for(i = 0 ; i <= n; ++ i){
28             for(int lucky:table){
29                 if(i + lucky <= n && dp[i + lucky] == total){
30                     ans.add(lucky);
31                     i += lucky-1;
32                     total--;
33                     break;
34                 }
35             }
36         }
37         int[] ret = new int[ans.size()];
38         for(i = 0 ; i < ans.size(); ++ i)
39             ret[i] = ans.get(i);
40         return ret;
41     }
42     
43 
44     
45     public ArrayList<Integer> calTable(){
46         ArrayList<Integer> table = new ArrayList<Integer>();
47         table.add(4);
48         table.add(7);
49         int i = 1;
50         while(i < 7){
51             ArrayList<Integer> temp = new ArrayList<Integer>();
52             for(int j = 0 ; j < table.size(); ++ j){
53                 int newItem = table.get(j) * 10;
54                 
55                 temp.add(newItem+4);
56                 temp.add(newItem+7);
57             }
58             i++;
59             table.addAll(temp);
60         }
61         return table;
62     }
63 }


posted @ 2009-12-25 16:13 jav7er 阅读(152) | 评论 (0)编辑 收藏
 
TopCoder SRM 405 Level 2 1000
一个理想的字符串,其中每个字母第一次出现的位置N,与这个字母在字符串中出现的次数M是相等的,求给定长度的字符串中最小的一个理想字符串

字符串长度小于100
相当于去搜索1~100中的一组不同的数
加起来等于长度L
同时每个数字都要小于等于比自己小的所有数的和加一
因为L比较小
所以用深搜就可以了
在这个过程中要注意深搜时候需要从大往小搜
这样才能满足“最小的”结果
搜索完之后的字符串构建的步骤因为StringBuffer用的不熟练
反而调试了很久
 1 import java.util.*;
 2 import java.util.regex.*;
 3 import java.text.*;
 4 import java.math.*;
 5 import java.awt.geom.*;
 6 
 7 public class IdealString
 8 {
 9     int[] table = new int[26];
10     int finalindex = 0;
11     int L;
12     
13     public String construct(int length)
14     {
15         Arrays.fill(table, 0);
16         L = length;
17         if(dfs(100)){
18             StringBuffer sb = new StringBuffer();
19             char c = 'A';
20             int i , j = 0;
21             for(i = 0 ; i < L; ++ i)
22                 sb.append(' ');
23             for(i = 0 ; i < finalindex; ++i){
24                 sb.setCharAt(table[i] - 1, c ++);
25                 table[i]--;
26             }
27             for(i = 0 ; i < L; ++ i){
28                 if(sb.charAt(i) != ' ')
29                     continue;
30                 while(table[j] == 0) j++;
31                 sb.setCharAt(i, (char)('A' + j));
32                 table[j]--;
33             }
34             return sb.toString();
35         }
36         return new String();
37     }
38     
39     boolean dfs(int num, int index, int sum){
40         table[index] = num;
41         int base = num + sum;
42         if(base == L){
43             table[index] = num;
44             finalindex = index + 1;
45             return true;
46         }
47         if(base > L)
48             return false;
49         int total = 0;
50         for(int i = 0 ; i <= index ; ++ i)
51             total += table[i];
52         for(int i = total + 1;  i >= num + 1-- i){            
53             if(base + i <= L && dfs(i, index +1, base))
54                 return true;
55         }
56         return false;
57     }
58 }


posted @ 2009-12-25 16:00 jav7er 阅读(134) | 评论 (0)编辑 收藏
 
TopCoder SRM 399 Level 2 1000
http://www.topcoder.com/stat?c=problem_statement&pm=8758&rd=12171
给定N和一个整数集合a,用不属于a的3个整数相乘得出离N最近的整数

N的范围1~1000
从小到大3重循环就可以解
理论上的复杂度高达1000^3
如果确实算一次我的电脑要跑到6秒
不过其实当乘积减去N已经超过之前的差额时就可以break了
所以计算量其实很小
加上break算一次只要零点零几秒
另外的陷阱是循环如果只是1~1000是不行的
有可能会用到比1000还大的因子
 1import java.util.*;
 2import java.util.regex.*;
 3import java.text.*;
 4import java.math.*;
 5import java.awt.geom.*;
 6
 7public class AvoidingProduct
 8{
 9    int SIZE = 1101;
10    
11    public int[] getTriple(int[] a, int n)
12    {
13        boolean[] table = new boolean[SIZE];
14        Arrays.fill(table, true);
15        for(int i = 0  ; i < a.length ; ++ i)
16            table[a[i]] = false;
17        int x,y,z;
18        int[] ans = new int[3];
19        Arrays.fill(ans, Integer.MAX_VALUE);
20        int gap = Integer.MAX_VALUE;
21        Outer:
22        for(x = 1 ; x < SIZE; ++ x){
23            if(table[x] == falsecontinue;
24            for(y = 1; y < SIZE; ++ y){
25                if(table[y] == falsecontinue;
26                for(z = 1 ; z < SIZE; ++ z){
27                    if(table[z] == falsecontinue;
28                    int total = x * y * z;
29                    int sub = n - total;
30                    if(Math.abs(sub) < gap){
31                        ans[0= x; ans[1= y; ans[2= z;
32                        gap = Math.abs(sub);
33                    }

34                    if(sub < 0 && Math.abs(sub) >= gap)
35                        break ;
36                }

37            }

38        }

39        return ans;
40    }

41    
42}
posted @ 2009-12-16 21:58 jav7er 阅读(116) | 评论 (0)编辑 收藏