hdu2037 今年暑假不AC(贪心算法基础--会场安排类似

来源:互联网 发布:音频合并软件 编辑:程序博客网 时间:2024/05/21 20:59

 

今年暑假不AC

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 22381    Accepted Submission(s): 11732

Problem Description
“今年暑假不AC?”
“是的。”
“那你干什么呢?”
“看世界杯呀,笨蛋!”
“@#$%^&*%...”

确实如此,世界杯来了,球迷的节日也来了,估计很多ACMer也会抛开电脑,奔向电视了。
作为球迷,一定想看尽量多的完整的比赛,当然,作为新时代的好青年,你一定还会看一些其它的节目,比如新闻联播(永远不要忘记关心国家大事)、非常6+7、超级女生,以及王小丫的《开心辞典》等等,假设你已经知道了所有你喜欢看的电视节目的转播时间表,你会合理安排吗?(目标是能看尽量多的完整节目)
 
Input
输入数据包含多个测试实例,每个测试实例的第一行只有一个整数n(n<=100),表示你喜欢看的节目的总数,然后是n行数据,每行包括两个数据Ti_s,Ti_e (1<=i<=n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。
 
Output
对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占一行。
Sample Input
121 33 40 73 815 1915 2010 158 186 125 104 142 90
 
Sample Output
5
 
Author
lcy
 
Source
ACM程序设计期末考试(2006/06/07)
 

2013-11-24 15:07:46Accepted2037171MS5088K1953 BJava1983210400

 

import java.util.Scanner;public class hdu2037今年暑假不AC {public static void main(String[] args) {// TODO Auto-generated method stub          Scanner sc=new Scanner (System.in);          while(true){          int n=sc.nextInt();          if(n==0)break;          int[]a=new int[n];          int[]b=new int[n];          for(int i=0;i<n;i++){          a[i]=sc.nextInt();          b[i]=sc.nextInt();//结束时间          }           for(int i=0;i<n-1;i++){          for(int j=i+1;j<n;j++){           if(b[i]>b[j]){             int e=a[i];             a[i]=a[j];             a[j]=e;                          int t=b[i];             b[i]=b[j];             b[j]=t;             }          }          }          System.out.println("排序后");          for(int i=0;i<n;i++)                  System.out.println(a[i]+":"+b[i]);                  System.out.println("=================");          System.out.println("打印那些活动对应的时间安排");                  ==============第一次做时写的一个算法==============        /*int count=1;          int min=b[0];//你要考虑只有一个的时候          for(int i=0;i<n-1;i++)//类似于冒泡排序的做法!!!                 for(int j=i+1;j<n;j++)//此算法不好之处在于,没有跳转,儿有很多多余的不要的操作!!!!          if(min<=a[j]){//第2013年11月24日出现”黑色三分钟“,就是在此处!一道原题,一个小时半未能解决!!>_<.深深地祭奠!          min=b[j];          count++;          // System.out.println(a[i]+" $ "+b[i]);          break;          }*/        =============第二次做时写的一个算法====有所改进===========            int count=1;          System.out.println(a[0]+" $ "+b[0]);          for(int i=0; i<n-1;i++)//必须i<n-1,类似于冒泡排序                       for(int j=i+1; j<n; j++)           if(b[i]<=a[j]){               i = j-1;//i会在改层for循环执行完毕后自身加1,所以与退回一步          count++;            System.out.println(a[j]+" $ "+b[j]);                   break;          }                       System.out.println(count);                   }}}


输出结果:

121 33 40 73 815 1915 2010 158 186 125 104 142 9排序后1:33:40:73:82:95:106:124:1410:158:1815:1915:20=================打印那些活动对应的时间安排1 $ 33 $ 45 $ 1010 $ 1515 $ 195


 上边的代码太挫!!(还是保留着,也是一个成长的过程)

 在有一大堆活动时,我们最先应该选择结束时间最早的那个,以利于之后能安排更多的活动,然后,再在剩下的可选的会场中选择最可能结束时间最早的那个,依次类推,直到无法安排任何活动为止。
也就是说,每次选择时,都应该贪婪的选择结束时间最短的那个活动

贪心算法是从局部的最优解去找全局的最优解,所以很有可能就像我们一样,只看眼前不看长远的话,很有可能是会走错路的。
所以,证明贪心算法的正确性就是一件极为重要的问题。

一般,贪心算法的证明多使用反证法

先假设存在一种方案B比我们刚才所说的方案A更好,也就是说,方案B能选出更多的活动。

现在假设方案B在第一次选择时没有选择结束时间最早的方案,则,方案B在选择第一个方案之后,剩余的方案中,起始时间一定要比方案A晚。所以方案B一定不可能比方案A选择出更多的活动如果方案B在第一次与方案A选择了相同的活动,而之后哪一次与方案A不同的话,则从此次之后,必然还会出现上面所说的情形。
故方案B一定不可能选出比方案一更多的活动。
所以,方案A就是最好的方案

import java.util.Scanner;public class Main {public static void main(String[] args) {// TODO Auto-generated method stub          Scanner sc=new Scanner (System.in);          while(true){          int n=sc.nextInt();          if(n==0)break;          int[]a=new int[n];          int[]b=new int[n];          for(int i=0;i<n;i++){          a[i]=sc.nextInt();          b[i]=sc.nextInt();//结束时间          }           for(int i=0;i<n-1;i++){          for(int j=i+1;j<n;j++){           if(b[i]>b[j]){             int e=a[i];             a[i]=a[j];             a[j]=e;                          int t=b[i];             b[i]=b[j];             b[j]=t;             }          }          }          int count=1;          int sta = b[0];          for(int j=1; j<n; j++)         if(sta <= a[j]){            sta = b[j];         count++;          }                       System.out.println(count);                   }}}

 java的类”结构体“排序:

import java.util.Arrays;import java.util.Scanner;public class nyoj_14_会场安排问题 {public static void main(String[] args) {           Scanner sc=new Scanner (System.in);          int  C = 1;          while(sc.hasNext()){          int n=sc.nextInt();                   E [] e = new E[n];          for(int i=0;i<n;i++){         e[i] = new E();         int x=sc.nextInt();         int y=sc.nextInt();         e[i].a = x>y?y:x;         e[i].b= x>y?x:y;          }           Arrays.sort(e);//一个类似以结构体的排序时需要用Comparator而非Comparable          int count=1;          int sta = e[0].b;          for(int j=1; j<n; j++)         if(sta < e[j].a){            sta = e[j].b;         count++;          }            System.out.println("Case "+(C++)+":");             System.out.println(count+".");                   }}}class E implements Comparable<E>{int a,b;@Overridepublic int compareTo(E o) { return this.b-o.b;} }