贪心算法and排序 杭电一题的启发

今年暑假不AC   Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)  Total Submission(s): 2063 Accepted Submission(s): 1137 

Problem Description

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

确实如此,世界杯来了,球迷的节日也来了,估计很多ACMer也会抛开电脑,奔向电视了。 作为球迷,一定想看尽量多的完整的比赛,当然,作为新时代的好青年,你一定还会看一些其它的节目,比如新闻联播(永远不要忘记关心国家大事)、非常6+7、超级女生,以及王小丫的《开心辞典》等等,假设你已经知道了所有你喜欢看的电视节目的转播时间表,你会合理安排吗?(目标是能看尽量多的完整节目)

Input

输入数据包含多个测试实例,每个测试实例的第一行只有一个整数n(n<=100),表示你喜欢看的节目的总数,然后是n行数据,每行包括两个数据Ti_s,Ti_e (1<=i<=n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。

Output

对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占一行。

Sample Input

12 1 3 3 4 0 7 3 8 15 19 15 20 10 15 8 18 6 12 5 10 4 14 2 9 0

Sample Output

5

我的代码::::

#include<stdio.h>

struct d {  

   int start;

    int end;

}; //选择用结构体

int main(){

 struct d a[100],temp;

   int i,j,n,count;

 while(scanf("%d",&n)&&n){

      for(i=0;i<n;i++)    

        scanf("%d%d",&a[i].start,&a[i].end);   

      for(i=0;i<n-1;i++)    

       for(j=0;j<n-1-i;j++)   

      if(a[j].end>a[j+1].end){    

           temp=a[j];                

           a[j]=a[j+1];

     a[j+1]=temp;   

          }    

 temp.end=a[0].end;count=1;  

   for(i=1;i<n;i++)     

 if(a[i].start>=temp.end){    

   count++;      

 temp.end=a[i].end;

     }             

printf("%d ",count);  

 }  return 0;  

}

下面是摘抄!!!!留着看

贪心算法的几个经典例子

1;区间相交问题

Time Limit:1000MS  Memory Limit:65536K Total Submit:118 Accepted:49

Description

给定x 轴上n个闭区间。去掉尽可能少的闭区间,使剩下的闭区间都不相交。
给定n个闭区间,计算去掉的最少闭区间数。

Input

输入数据的第一行是正整数n(n≤100),表示闭区间数。接下来的n行中,每行有2 个整数,分别表示闭区间的2个数端点。

Output

将计算出的去掉的最少闭区间数输出。

Sample Input

310 2010 1520 15

Sample Output

2

Source

#include <stdio.h>

#include <stdlib.h>

struct node

{

    int l;

    int r;

}s[101];

int cmp(const void*a,const void*b)

{

    return (*(struct node*)a).r-(*(struct node*)b).r;

}

int main()

{

   int i,n,t;

   scanf("%d",&n);

   for(i=0;i<n;i++)

   {

       scanf("%d %d",&s[i].l,&s[i].r);

       if(s[i].l>s[i].r)

       {

           t=s[i].l;

           s[i].l=s[i].r;

           s[i].r=t;

       }

   }

   qsort(s,n,sizeof(s[0]),cmp);

   int star=s[0].r;

   t=1;//第一个数据

   for(i=1;i<n;i++)//循环选出最多的不想交的闭区间

   {

       if(s[i].l>star)

       {

           star=s[i].r;

           t++;

       }

   }

   printf("%d ",n-t);//总的区间数减去t就是去点的区间数了

2;会场安排问题

Time Limit:1000MS  Memory Limit:65536K Total Submit:252 Accepted:76

Description

假设要在足够多的会场里安排一批活动,并希望使用尽可能少的会场。设计一个有效的贪心算法进行安排。(这个问题实际上是著名的图着色问题。若将每一个活动作为图的一个顶点,不相容活动间用边相连。使相邻顶点着有不同颜色的最小着色数,相应于要找的最小会场数。)
对于给定的k个待安排的活动,计算使用最少会场的时间表。

Input

输入数据的第一行有1 个正整数k(k≤10000),表示有k个待安排的活动。接下来的k行中,每行有2个正整数,分别表示k个待安排的活动开始时间和结束时间。时间以0 点开始的分钟计。

Output

输出一个整数,表示最少会场数。

Sample Input

51 2312 2825 3527 8036 50

Sample Output

3

至今未能理解为什么要把开始和结束时间都排序。。

然后能连接在一起的就连接在一起。。不能的就要另开会场

#include<stdio.h>

#include<stdlib.h>

int cmp(const void *a, const void *b)

{

    return *(int*)a > *(int*)b ? 1 : -1;

}

int arrange(int *begin, int *end, int s, int n)

{

    int count = 0;

    int i = s + 1;

    if(n > 0)

    {

        count = 1;

        for(; i < n; i++)//循环完后,可以在一起举行的,都来凝结在了一起给它一个会场,剩下的就每个会议分一个会场

        {

            if(begin[i] >= end[s])

            {

                s++; 

            }

            else

            {

                count++; 

            }

        }

    }

    return count;

}

int main()

{

    int n,t;

    int begin[10000];

    int end[10000];

    scanf("%d",&n);

    for(int i = 0; i < n; i++)

    {

        scanf("%d %d",&begin[i],&end[i]);

    }

    qsort(begin, n, sizeof(begin[0]), cmp);

    qsort(end, n, sizeof(end[0]), cmp);

    t=arrange(begin, end, 0, n);

    printf("%d ",t);

    return 0;

}

3

区间覆盖问题

Time Limit:1000MS  Memory Limit:65536K Total Submit:106 Accepted:54

Description

设x1 , x2 ,…… , xn 是实直线上的n 个点。用固定长度的闭区间覆盖这n 个点,至少需要多少个这样的固定长度闭区间?
对于给定的实直线上的n个点和闭区间的长度k,设计解此问题的有效算法,计算覆盖点集的最少区间数,并证明算法的正确性。

Input

输入数据的第一行有2 个正整数n和k(n≤10000,k≤100),表示有n个点,且固定长度闭区间的长度为k。接下来的1 行中,有n个整数,表示n个点在实直线上的坐标(可能相同)。

Output

输出一个整数,表示计算出的最少区间数输出。

Sample Input

7 3 1 2 3 4 5 -2 6

#include <stdio.h>

#include <stdlib.h>

int cmp(const void*a,const void*b)

{

    return *(int*)a-*(int*)b;

}

int main()

{

   int n,k,a[10000],i,p,t;

   scanf("%d %d",&n,&k);

   t=0;

       for(i=0;i<n;i++)

       scanf("%d",&a[i]);

       qsort(a,n,sizeof(a[0]),cmp);//从小到大排序

        i=0;

       while(i<n)

       {

          p=a[i]+k;

           while(a[i]<=p)//能覆盖的就

           i++;//下移

           t++;//不能了区间加1

       }

       printf("%d ",t);

    return 0;

}

Sample Output

3

下面是排序!!!!

1)“冒泡法
冒泡法大家都较熟悉。其原理为从a[0]开始,依次将其和后面的元素比较,若a[0]>a[i],则交换它们,一直比较到a[n]。同理对a[1],a[2],...a[n-1]处理,即完成排序。下面列出其代码:
void bubble(int *a,int n) /*定义两个参数:数组首地址与数组大小*/
{
int i,j,temp;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++) /*注意循环的上下限*/
if(a[i]>a[j]) {
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
冒泡法原理简单,但其缺点是交换次数多,效率低。
下面介绍一种源自冒泡法但更有效率的方法“选择法”。
(2)“选择法”
选择法循环过程与冒泡法一致,它还定义了记号k=i,然后依次把a[k]同后面元素比较,若a[k]>a[j],则使k=j.最后看看k=i是否还成立,不成立则交换a[k],a[i],这样就比冒泡法省下许多无用的交换,提高了效率。
void choise(int *a,int n)
{
int i,j,k,temp;
for(i=0;i<n-1;i++) {
k=i; /*给记号赋值*/
for(j=i+1;j<n;j++)
if(a[k]>a[j]) k=j; /*是k总是指向最小元素*/
if(i!=k) { /*当k!=i是才交换,否则a[i]即为最小*/
temp=a[i];
a[i]=a[k];
a[k]=temp;
}
}
}
选择法比冒泡法效率更高,但说到高效率,非“快速法”莫属,现在就让我们来了解它。
(3)“快速法”
快速法定义了三个参数,(数组首地址*a,要排序数组起始元素下标i,要排序数组结束元素下标j). 它首先选一个数组元素(一般为a[(i+j)/2],即中间元素)作为参照,把比它小的元素放到它的左边,比它大的放在右边。然后运用递归,在将它左,右两个子数组排序,最后完成整个数组的排序。下面分析其代码:
void quick(int *a,int i,int j)
{
int m,n,temp;
int k;
m=i;
n=j;
k=a[(i+j)/2]; /*选取的参照*/
do {
while(a[m]<k&&m<j) m++; /* 从左到右找比k大的元素*/
while(a[n]>k&&n>i) n--; /* 从右到左找比k小的元素*/
if(m<=n) { /*若找到且满足条件,则交换*/
temp=a[m];
a[m]=a[n];
a[n]=temp;
m++;
n--;
}
}while(m<=n);
if(m<j) quick(a,m,j); /*运用递归*/
if(n>i) quick(a,i,n);
}
(4)“插入法
插入法是一种比较直观的排序方法。它首先把数组头两个元素排好序,再依次把后面的元素插入适当的位置。把数组元素插完也就完成了排序。
void insert(int *a,int n)
{
int i,j,temp;
for(i=1;i<n;i++) {
temp=a[i]; /*temp为要插入的元素*/
j=i-1;
while(j>=0&&temp<a[j]) { /*从a[i-1]开始找比a[i]小的数,同时把数组元素向后移*/
a[j+1]=a[j];
j--;
}
a[j+1]=temp; /*插入*/
}
}
(5)“shell法”
shell法是一个叫 shell美国人与1969年发明的。它首先把相距k(k>=1)的那几个元素排好序,再缩小k值(一般取其一半),再排序,直到k=1时完成排序。下面让我们来分析其代码:
void shell(int *a,int n)
{
int i,j,k,x;
k=n/2; /*间距值*/
while(k>=1) {
for(i=k;i<n;i++) {
x=a[i];
j=i-k;
while(j>=0&&x<a[j]) {
a[j+k]=a[j];
j-=k;
}
a[j+k]=x;
}
k/=2; /*缩小间距值*/
}
}
上面我们已经对几种排序法作了介绍,现在让我们写个主函数检验一下。
#include<stdio.h>
/*别偷懒,下面的"..."代表函数体,自己加上去哦!*/
void bubble(int *a,int n)
{
...
}
void choise(int *a,int n)
{
...
}
void quick(int *a,int i,int j)
{
...
}
void insert(int *a,int n)
{
...
}
void shell(int *a,int n)
{
...
}
/*为了打印方便,我们写一个print吧。*/[code]
void print(int *a,int n)
{
int i;
for(i=0;i<n;i++)
printf("%5d",a[i]);
printf(" ");
}
main()
{ /*为了公平,我们给每个函数定义一个相同数组*/
int a1[]={13,0,5,8,1,7,21,50,9,2};
int a2[]={13,0,5,8,1,7,21,50,9,2};
int a3[]={13,0,5,8,1,7,21,50,9,2};
int a4[]={13,0,5,8,1,7,21,50,9,2};
int a5[]={13,0,5,8,1,7,21,50,9,2};
printf("the original list:");
print(a1,10);
printf("according to bubble:");
bubble(a1,10);
print(a1,10);
printf("according to choise:");
choise(a2,10);
print(a2,10);
printf("according to quick:");
quick(a3,0,9);
print(a3,10);
printf("according to insert:");
insert(a4,10);
print(a4,10);
printf("according to shell:");
shell(a5,10);
print(a5,10);
}
原文地址:https://www.cnblogs.com/shaomg/p/3554264.html