
/**//*
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)
评论()
收藏
举报