码迷,mamicode.com
首页 > 其他好文 > 详细

Timus 1005 & 1009

时间:2015-03-16 21:04:49      阅读:222      评论:0      收藏:0      [点我收藏+]

标签:

Problem 1005

问题:一堆石头划分问题,将一堆石头划分成两堆,使这两堆石头之间的重量差最小。

输入:第一行---石头的总数量(1~20)

           第二行---各石头的重量,之间用空格间隔(每个石头重量在1~100000)

输出:两堆石头最小的重量差。

技术分享

实现代码:

using System;

namespace Q1005
{
    class Program
    {
        static void Main(string[] args)
        {
            int num = Int16.Parse(Console.ReadLine());
            int[] array = new int[num];
            string[] str = Console.ReadLine().Split();
            for (int i = 0; i < num; i++)
                array[i] = Int32.Parse(str[i]);
            int min = MinDifferent(array);
            Console.WriteLine("{0}", min);
        }
        //0-1背包方法
        static int MinDifferent(int[] array)
        {
            int sum=0;
            for (int i = 0; i < array.Length; i++)
                sum += array[i];
            int[] dp = new int[sum+1];
            //背包问题,此背包能够容纳全部的值,且物品的价值等于物品的大小
            //且dp[k]记录的是背包容量为k时的最大值
            for (int i = 0; i < array.Length; i++)
                for (int k = sum; k >= array[i]; k--)
                    dp[k] = Math.Max(dp[k], dp[k - array[i]] + array[i]);
            int min = Int32.MaxValue;
            //找出其中容量为k时的最大值使之与sum/2最接近
            for (int i = 0; i <= sum; i++)
                if (Math.Abs(sum/2 - dp[i]) < min)
                    min = Math.Abs(sum / 2 - dp[i]);
            return (min*2+sum%2);
        }
    }
}

主要知识点:

  1. 0-1背包 :参见http://www.cnblogs.com/fly1988happy/archive/2011/12/13/2285377.html

此问题的暴力解法,参见:比较灵活的暴力法,利用移位http://www.cnblogs.com/skyivben/archive/2008/07/26/1251907.html

或利用每个石头之间总共有技术分享的+,-情况:

http://blog.163.com/yinson_lin/blog/static/22120172008112552832626/

Problem 1009

问题:N位的K进制数个数,其中此K进制数个数有一定的限制条件:

1. 两个位之间包含两个0及以上0的不属于,如 10010不属于5进制数。

2. 最高位不允许为0,如011不属于3进制数。

输入:第一行---N(位数---取N>=2)

           第二行---K(进制---取2<=K<=10)

且要求N+K<=18

输出:符合要求的K进制数总个数

技术分享

实现代码:

using System;

namespace Q1009
{
    class Program
    {
        static void Main(string[] args)
        {
            int n = Int16.Parse(Console.ReadLine());
            int k = Int16.Parse(Console.ReadLine());

            Console.WriteLine(DPTotal(k, n));
            Console.WriteLine(TotalNum(k, n));
            Console.ReadKey();
        }

        static int TotalNum(int k, int n)
        {
            int[] store = new int[n + 1];
            //1位数和2位数的情况
            store[1] = k - 1;
            store[2] = (k - 1) * k;
            //采用归纳法得出的结论
            for (int i = 3; i <=n; i++)
                store[i] = (k - 1) * (store[i - 1] + store[i - 2]);
            return store[n];
        }
   }
}

主要知识点:

  1. 在于获取表达式 store[i] = (k - 1) * (store[i - 1] + store[i - 2]);

技术分享

进一步归纳便可得出上式。

更详细的见:http://www.cnblogs.com/skyivben/archive/2008/07/04/1235062.html

方法二:暴力求解

static int DPTotal(int k,int n)
{
    //dp[i,j]用于记录第i位第j个值得个数
    int[,] dp = new int[n+1, k];
    for (int i = 1; i < k; i++)
        dp[1, i] = 1;
    for(int i=2;i<n+1;i++)
        for(int j=0;j<k;j++)
        {
            if (j == 0)
                for(int m=1;m<k;m++)
                    dp[i, j] += dp[i - 1, m];
            if(j!=0)
                for (int m = 0; m < k; m++)
                    dp[i, j] += dp[i - 1, m];
        }
    int sum=0;
    for (int i = 0; i < k; i++)
        sum += dp[n, i];
    return sum;
}

主要知识点:用数组记录每个结果。

但比较奇怪的发现:方法2既然比方法1用时更短(感觉明显不正常吧!!!)

技术分享

上面是方法2的结果=。=

Timus 1005 & 1009

标签:

原文地址:http://www.cnblogs.com/Paul-chen/p/4342722.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!