/*
ID: sdjllyh1
PROG: barn1
LANG: JAVA
complete date: 2008/10/7
efficiency: O(c * lg(c))
author: LiuYongHui From GuiZhou University Of China
more article: www.cnblogs.com/sdjls


 * ===题目解析===
 * 术语:状态S(i)
 * 状态S(i)是指在牛棚(stall)上放置i个木板(block)后使得所有有牛儿居住的stall均被覆盖时所得到的状态。
 * 由此可知这种状态可能不止一个。
 * 
 * 术语:|S(i)|
 * |S(i)|表示状态S(i)所覆盖的牛棚(stall)的总数,也就是木板(block)的长度
 * 
 * 术语:状态是最优的
 * 说一个状态S(i)是最优的,当且仅当不存在S'(i)使得|S'(i)| < |S(i)|
 * 最优的状态也可能有多个。
 * 
 * 术语:空白(blank)
 * 空白(blank)指一段连续的没有牛儿居住的牛棚,我们只考虑两边不能在增加的空白,即左、右两边要么有牛居住,要么没有牛棚。
 * 
 * 术语:|空白(blank)|
 * |k|指空白k的长度
 * 
 * 术语:增加block过程
 * 增加block过程就是在一个状态上找出一段被覆盖的空白,把覆盖这个空白的木板挖去空白所对应的位置,即一个木板变为两个,被覆盖的空白少了一个。
 * 在状态为S(i)时调用此过程后状态变为S(i+1)。
 * 
 * 此题的算法是这样的,首先用一块木板从第一个牛的位置覆盖到最后一个牛的位置。
 * 然后反复调用“增加block过程”,直到所使用的木板数达到题目给出的限制,或空白全部被填满。
 * 这样得到的状态S(p)就是最优状态。[p等于给出的可用木板数与空白数的较小值]
 * 
 * 这是一个贪心算法,下面使用一个循环不变式证明它的正确性,这里假设没有两个空白具有相同的长度(因为当最长的空白有多个时可以选择任意一个,所以这种假设是可行的)。
 * 循环不变式:在首先用一块木板从第一个牛的位置覆盖到最后一个牛的位置后(得到状态S(1)),每次调用“增加block过程”后得到的状态S(i)均是最优的。
 * 初始:
 *        容易看出S(1)是最优的。
 * 中间:
 *        假设S(k)是最优的,则使用“增加block过程”后S(k+1)也是最优的,下面用反证法来证明。
 * 如果S(k+1)不是最优的,则存在S'(k+1)最优,使得 |S'(k+1)| < |S(k+1)|,且S'(k+1)不等于S(k+1)
 * 设在S(k)到S(k+1)的转变中我们去掉的那个最长的空白为b,则有 |S(k+1)| = |S(k)| - |b|,
 * 又因为|S'(k+1)| < |S(k+1)|,所以有|S'(k+1)| < |S(k)| - |b|,即 |S(k)| > |S'(k+1)| + |b| <1式>,
 *  * 当S'(k+1)没有覆盖b时,我们可以把b两头的木板连起来覆盖b得到S'(k),且有 |S'(k)| = |S'(k+1)| + |b|,
 * 根据<1式>有 |S(k)| > |S'(k)| ,这与假设S(k)最优矛盾。
 * 当S'(k+1)覆盖了b时,因为b是S(k)中最长的空白,则S'(k+1)中一定存在一个没有覆盖的空白d,使得 |d| < |b|,
 * 这是因为如果d不存在的话表明前k次删除空白时我们删除了最长的k个空白(b是第k长的),这意味着S'(k+1)等于S(k+1),别忘了我们假设没有两个空白具有相同的长度。
 * 因此S'(k+1)覆盖了b时d一定存在,此时如果在S'(k+1)中交换b、d(不覆盖b,而覆盖d),则可得S''(k+1),
 * 又因为 |d| < |b| ,所以 |S''(k+1)| < |S'(k+1)|,这与S'(k+1)最优矛盾。
 * 
 * 由此可知S(k+1)是最优的,即算法正确。
*/


import java.io.*;
import java.util.*;

public class barn1
{
    
private static int[] blanks;//blanks[3]=5,表示第3个空白(没有牛的位置)的长度为5
    private static int m;//可以使用的block数目
    private static int blankCount;//空白的总数
    private static int totalNumber;//total number of stalls blocked(总共覆盖的stall数目)

    
public static void main(String[] args) throws IOException
    
{
        init();
        run();
        output();
        System.exit(
0);
    }

    
    
    
private static void run()
    
{
        Arrays.sort(blanks);
        m
--;//已开始我们已经使用了一个block,它覆盖了第一个非空白到最后一个非空白的stall
        while ((m>0&& (blankCount>0) )//当还有更多的block可用且还有blank没有被覆盖时
        {
            totalNumber 
-= blanks[blankCount - 1];
            blankCount
--;
            m
--;
        }

    }


    
//初始化函数是对全局变量的初始化,不做注释
    private static void init() throws IOException
    
{
        BufferedReader f 
= new BufferedReader(new FileReader("barn1.in"));
        StringTokenizer st 
= new StringTokenizer(f.readLine());
        
int s, c;
        m 
= Integer.parseInt(st.nextToken());
        s 
= Integer.parseInt(st.nextToken());
        c 
= Integer.parseInt(st.nextToken());


        
int[] cowIndexs = new int[c];
        
for (int i = 0; i < c; i++)
        
{
            cowIndexs[i] 
= Integer.parseInt(f.readLine());
        }

        Arrays.sort(cowIndexs);
        totalNumber 
= cowIndexs[c - 1- cowIndexs[0+ 1;
        f.close();

        blanks 
= new int[c];
        blankCount 
= 0;
        
int tmp1 = cowIndexs[0];
        
int tmp2;
        
for (int i = 1; i < c; i++)
        
{
            tmp2 
= cowIndexs[i];
            
if (tmp2 - tmp1 - 1 > 0)
            
{
                blanks[blankCount] 
= tmp2 - tmp1 - 1;
                blankCount
++;
            }

            tmp1 
= tmp2;
        }

        
int[] tmpBlanks = new int[blankCount];
        System.arraycopy(blanks, 
0, tmpBlanks, 0, blankCount);
        blanks 
= tmpBlanks;
    }



    
private static void output() throws IOException
    
{
        PrintWriter out 
= new PrintWriter(new BufferedWriter(new FileWriter("barn1.out")));
        out.println(totalNumber);
        out.close();
    }

}

posted on 2008-10-07 17:07  刘永辉  阅读(971)  评论(4)    收藏  举报