贪心算法小结。今年暑假不AC&&Radar Installation&&Y2K Accounting Bug&&Minimal Coverage

                                                                           今年暑假不AC:http://acm.hdu.edu.cn/showproblem.php?pid=2037

一个简单的贪心例题:

思路:就是自己看:

 1 #include <iostream> 
 2 
 3 using namespace std; 
 4 
 5 int main() 
 6 
 7 {                             
 8 
 9     int a[100],b[100]; 
10 
11     int n; 
12 
13     int e=0; 
14 
15     int cont=0; 
16 
17     while(cin>>n&&n!=0){ 
18 
19         cont=0; 
20 
21         for(int i=0;i<n;i++) 
22 
23             cin>>a[i]>>b[i]; 
24 
25         for(int i=0;i<n;i++) 
26 
27             for(int j=i;j<n;j++)
28 
29                    { 
30 
31                 if(b[i]>b[j])
32 
33                    { 
34 
35                     swap(b[i],b[j]);  //交换位置
36 
37                     swap(a[i],a[j]);  //虽然只是冒泡法,这个问题还不会超时!
38 
39                 }                
40 
41             } 
42 
43         //取第一个        
44 
45         cont++;
46 
47         e=b[0]; 
48 
49         for(int i=1;i<n;i++){ 
50 
51             if(a[i]>=e) { 
52 
53                 cont++; 
54 
55                 e=b[i]; 
56 
57             }  
58 
59         } 
60 
61         cout<<cont<<endl; 
62 
63     } 
64 
65     return 0; 
66 
67 }  

Radar Installationhttp://poj.org/problem?id=1328

也是贪心算法。

思路:先把每个点对应圆的取值范围表示出来,此题就转化成为线段相交的问题。之后就是左端排序,再求他们之间分成几块。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
int main()
{
    int n,m,i,a[1005],b[1005],j,s,q=0,k=0,sd;
    double c[1005],d[1005],e[1005],h;//要用double型!

  while(scanf("%d %d",&n,&m)!=EOF)
  {
      q++;k=0;
      if(n==0&&m==0)
        break;
      for(i=0;i<n;i++)
        {scanf("%d %d",&a[i],&b[i]);
        if(b[i]>m)
            k=1;
        }
        if(k==1)
            printf("Case %d: -1
",q);//
        else
        {
      for(i=0;i<n;i++)
        for(j=i;j<n;j++)
      {
          if(a[i]>a[j])
          {
            swap(a[i],a[j]);
            swap(b[i],b[j]);
          }
      }
       for(i=0;i<n;i++)
      {
          c[i]=sqrt(m*m-b[i]*b[i]);
      }
      for(i=0;i<n;i++)
      {
          d[i]=a[i]-c[i];
          e[i]=a[i]+c[i];
      }
      s=1;
      h=e[0];
      for(i=1;i<n;i++)
          if(d[i]>h)
          {
              h=e[i];
              s++;
          }
          else if(e[i]<h)
                 h=e[i];
      printf("Case %d: %d
",q,s);}

  }
   return 0;
}

 Y2K Accounting Bug  http://poj.org/problem?id=2586

题目难理解,但做起来不难。以下题意解释来自:優YoU http://user.qzone.qq.com/289065406/blog/1299234147

实际上;只要讨论5种情况即可;(任一月固定盈余s,或固定亏损d).

SSSSDSSSSDSS   4s<d       保证“连续5个月必亏损”,每连续5个月种至少1个月D,

                          保证可能有全年最大盈余,每连续5个月中至多4个月S

SSSDDSSSDDSS   3s<2d      保证“连续5个月必亏损”,每连续5个月种至少2个月D,

保证可能有全年最大盈余,每连续5个月中至多3个月S

SSDDDSSDDDSS   2s<3d      保证“连续5个月必亏损”,每连续5个月种至少3个月D,

保证可能有全年最大盈余,每连续5个月中至多2个月S

SDDDDSDDDDSD   s<4d       保证“连续5个月必亏损”,每连续5个月种至少4个月D,

保证可能有全年最大盈余,每连续5个月中至多1个月S

DDDDDDDDDDDD   s>=4d      保证“连续5个月必亏损”,每连续5个月种至少5个月D,

每月亏损,此情况全年必亏损

要注意的是,前4种情况都仅仅是“可能有全年的盈余”,而不是“一定有全年的盈余”。

但是若果一旦有盈余,必定是最大盈余

#include<iostream>
#include<stdio.h>
using namespace std;
int main()
{
    int n,m,t;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)
            break;
        if(m>n*4)
        {
            t=n*10-m*2;
            if(t>0)
                printf("%d
",t);
            else
                printf("Deficit
");
        }
        else if(m*2>n*3)
        {
            t=n*8-m*4;
            if(t>0)
                printf("%d
",t);
            else
                printf("Deficit
");
        }
        else if(m*3>n*2)
        {
            t=n*6-m*6;
            if(t>0)
                 printf("%d
",t);
            else
                printf("Deficit
");
        }
        else if(m*4>n)
        {
            t=n*3-m*9;
            if(t>0)
                printf("%d
",t);
            else
                printf("Deficit
");
        }
        else
             printf("Deficit
");
    }
    return 0;
}

Minimal Coveragehttp://poj.org/problem?id=2620

照样的贪心的方法,但注意这里排序一定不能用冒泡法!!!!!直接超时!

题意就是:数轴上有n个闭区间[ai,bi],选择尽量少的区间覆盖一条指定的线段[s,t]。

本人第一次用sort()来排序,这里要用结构体。贪心的算法一般就是先排序,再从小到大找关系就行了。

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
struct line
{
    int left;
    int right;
}a1[100000];
bool comp(line i,line j)
{
    if(i.left<j.left)
        return true;//这里是从小到大的排序。只要看left就行了right跟着一起排的。正符合题意。要想从大到小就是把小于符号变成大于!
    return false;从这里似乎看出对于结构体的这种排序,如果只说明一种,其他就默认地跟着那样排了!
}
int main()
{
    int n,a,b,d=0,i,j,x=0,w=0,h,y=0,max1=0,max2,c[100000];
   scanf("%d",&n);
        while(scanf("%d %d",&a,&b)!=EOF)
        {
            if(a==0&&b==0)
                break;
                if(a<n&&b>0)
            {a1[d].left=a;a1[d].right=b;d++;}
        }
        sort(a1,a1+d,comp);
       for(;;)
        {
            y=0;
            max2=max1;
            max1=0;
            for(i=0;i<d;i++)
        {
            if(a1[i].left<=max2&&a1[i].right>max2)
            {
                if(a1[i].right>max1)
                {
                    max1=a1[i].right;c[x]=i;
                }
                y=1;
            }
    }
        x++;
        if(y!=1)
        {w=1;break;}
        if(max1>=n)
        {w=2;break;
        }
    }
    if(w==1)
        printf("No solution
");
    if(w==2)
    {
        printf("%d
",x);
        for(i=0;i<x;i++)
        {
            printf("%d %d
",a1[c[i]].left,a1[c[i]].right);
        }
    }
    return 0;
}

 关于sort()一些常见用法:

sort(a,a+n);默认的从小到大排序;

等价于:

bool comp(int a,int b)
{
return a<b;
}
sort(a,a+10,comp);

而要从大到小排序:

bool comp(int a,int b)
{
return a>b;
}
sort(a,a+10,comp);

原文地址:https://www.cnblogs.com/tt123/p/3208424.html