贪心算法(2)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a1128o/article/details/51959059

King’s Cake

HDU 5640 http://acm.hdu.edu.cn/showproblem.php?pid=5640

It is the king’s birthday before the military parade . The ministers prepared a rectangle cake of size n×m(1≤n,m≤10000) . The king plans to cut the cake himself. But he has a strange habit of cutting cakes. Each time, he will cut the rectangle cake into two pieces, one of which should be a square cake.. Since he loves squares , he will cut the biggest square cake. He will continue to do that until all the pieces are square. Now can you tell him how many pieces he can get when he finishes.

Input
The first line contains a number T(T≤1000), the number of the testcases.

For each testcase, the first line and the only line contains two positive numbers n,m(1≤n,m≤10000).

Output
For each testcase, print a single number as the answer.

Sample Input
2
2 3
2 5
Sample Output
3
4

给你一个形状为矩形的蛋糕,每一次把矩形切割为两部分,其中一部分为最大的正方形,另外一部分再继续切割直到全部都为正方形为止,求切割完之后一共有多少块蛋糕
对于长和宽分别为n,m的矩形,一次切割面积最大的正方形的边长x = min(m,n),剩余部分的长宽分别为max(m,n)-x和x,然后再对子问题求解

#include<iostream>
using namespace std;

int main(){
    int t,n,m;
    int count,x,y;
    cin>>t;
    while(t--){
        cin>>n>>m;
        count = 1;
        while(m != n){
            x = m>n?m:n;
            y = m>n?n:m;
            x -= y;
            count++;
            m = x;
            n = y;
        }
        cout<<count<<endl;
    }
    return 0;
}

King’s Phone

HDU 5641 http://acm.hdu.edu.cn/showproblem.php?pid=5641

In a military parade, the King sees lots of new things, including an Andriod Phone. He becomes interested in the pattern lock screen.

The pattern interface is a 3×3 square lattice, the three points in the first line are labeled as 1,2,3, the three points in the second line are labeled as 4,5,6, and the three points in the last line are labeled as 7,8,9。The password itself is a sequence, representing the points in chronological sequence, but you should follow the following rules:

  • The password contains at least four points.
  • Once a point has been passed through. It can’t be passed through again.

    扫描二维码关注公众号,回复: 4390620 查看本文章
  • The middle point on the path can’t be skipped, unless it has been passed through(3427 is valid, but 3724 is invalid).

His password has a length for a positive integer k(1≤k≤9), the password sequence is s1,s2…sk (0si<INTMAX) , he wants to know whether the password is valid. Then the King throws the problem to you.

Input
The first line contains a number T (0<T100000) , the number of the testcases.

For each test case, there are only one line. the first first number k,represent the length of the password, then k numbers, separated by a space, representing the password sequence s1,s2…sk.

Output
Output exactly T lines. For each test case, print valid if the password is valid, otherwise print invalid

Sample Input
3
4 1 3 6 2
4 6 2 1 3
4 8 1 6 7

类似于现在的手机屏保图案密码。已知屏幕上为3*3的九个数字,给你一个密码,若存在以下情况则密码无效:该密码不止一次经过同一个数字;密码长度小于4;两个点之间跳过一个没被经过的点

这是AC的代码,在这份代码直接之前还有很多版本。思路就是有两个判断函数:一个判断密码长度是否小于四以及该密码是否有重复经过同一个点;第二个判断函数判断是否存在两个点之间经过一个未被经过的点,这里采用枚举,因为一共只有九个点,把中间可能会经过另外一个点的情况都列出来,例如(1,3,2)1和3之间经过了点2,还有(1,7,4),(1,9,5),(4,6,5),(7,9,8),(2,8,5),(3,7,5),(3,9,6).

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int k,a[12],vis[12];
int check1(){
    if(k<4)return 0;
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=k;i++){
        if(a[i]>9||a[i]<1||vis[a[i]]==1){
            return 0;
        }
        else {
            vis[a[i]]=1;
        }
    }
    return 1;
}
int check2(){
    memset(vis,0,sizeof(vis));
    for(int i=1;i<k;i++){
        if(a[i]==1&&a[i+1]==3&&vis[2]==0)return 0;
        if(a[i]==3&&a[i+1]==1&&vis[2]==0)return 0;
        if(a[i]==1&&a[i+1]==7&&vis[4]==0)return 0;
        if(a[i]==7&&a[i+1]==1&&vis[4]==0)return 0;
        if(a[i]==1&&a[i+1]==9&&vis[5]==0)return 0;
        if(a[i]==9&&a[i+1]==1&&vis[5]==0)return 0;
        if(a[i]==3&&a[i+1]==9&&vis[6]==0)return 0;
        if(a[i]==9&&a[i+1]==3&&vis[6]==0)return 0;
        if(a[i]==7&&a[i+1]==3&&vis[5]==0)return 0;
        if(a[i]==3&&a[i+1]==7&&vis[5]==0)return 0;
        if(a[i]==7&&a[i+1]==9&&vis[8]==0)return 0;
        if(a[i]==9&&a[i+1]==7&&vis[8]==0)return 0;
        if(a[i]==4&&a[i+1]==6&&vis[5]==0)return 0;
        if(a[i]==6&&a[i+1]==4&&vis[5]==0)return 0;
        if(a[i]==2&&a[i+1]==8&&vis[5]==0)return 0;
        if(a[i]==8&&a[i+1]==2&&vis[5]==0)return 0;
        vis[a[i]]=1;
    }
    return 1;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&k);
        for(int i=1;i<=k;i++){
            scanf("%d",&a[i]);
        }
        if(check1()==0||check2()==0)cout<<"invalid"<<"\n";
        else cout<<"valid"<<"\n";
    }
    return 0;
}

报错的版本。判断都在主函数中进行,对于判断两点之间是否经过未经过的点,是按点分类然后进行判断的,但是提交的时候报错了

#include<stdio.h>
int s[10];
int main(){

    int k,i,flag;
    int t;
    //cin>>t;
    scanf("%d",&t);
    while(t--){

        flag = 0;
        scanf("%d",&k);
        //cin>>k;     //密码长度

        for(i = 0;i < k;i++){
            scanf(" %d",&s[i]); 
            if(s[i] < 1 || s[i] > 9 || a[s[i]] == 1){
                flag = 1;
            }
            a[s[i]] = 1;
        }
        if(k < 4){
        flag = 1;
       }
    memset(a,0,sizeof(a));
    for(int i = 1;i <= k;i++){
        if(a[i]>9||a[i]<1||a[s[i]]==1){
            flag = 1;
        }
        else{
            a[s[i]] = 1;
        }
    }
    for(i = 1;i < k;i++){
        a[s[0]] = 0;
    }
        for(i = 1;i < k;i++){
           if(a[s[i]] == 1){
               flag = 1;
           }
           else{
                switch(s[i-1]){
                case 1: if((s[i] == 7 && a[4] == 0) || (s[i] == 9 && a[5] == 0) || (s[i] == 3 && a[2] == 0)){
                         flag = 1;
                        }
                        break;
                case 2: if(s[i] == 8 && a[5] == 0){
                           flag = 1;
                        }
                        break;
                case 3: if((s[i] == 7 && a[5] == 0) || (s[i] == 9 && a[6] == 0) || (s[i] == 1 && a[2] == 0)){
                            flag = 1;
                        }
                        break;
                case 4: if(s[i] == 6 && a[5] == 0){
                            flag = 1;
                        }
                        break;  
                case 5: break;
                case 6: if(s[i] == 4 && a[5] == 0){
                           flag = 1;
                        }
                        break;
                case 7: if((s[i] == 1 && a[4] == 0) || (s[i] == 9 && a[8] == 0) ||(s[i] == 3 && a[5] == 0)){
                            flag = 1;
                        }
                        break;
                case 8: if(s[i] == 2 && a[5] == 0){
                            flag = 1;
                        }
                        break;
                case 9: if((s[i] == 1 && a[5] == 0) || (s[i] == 3 && a[6] == 0) ||(s[i] == 7 && a[8] == 0)){
                            flag = 1;
                        }
                        break;
                }
            a[s[i]] = 1;    
            }
        }
        if(flag == 1){  
            printf("invalid\n");
        }
        else{
            printf("valid\n");
        }
    }
    return 0;
}

Radar Installation

POJ 1328 http://poj.org/problem?id=1328

Assume the coasting is an infinite straight line. Land is in one side of coasting, sea in the other. Each small island is a point locating in the sea side. And any radar installation, locating on the coasting, can only cover d distance, so an island in the sea can be covered by a radius installation, if the distance between them is at most d.

We use Cartesian coordinate system, defining the coasting is the x-axis. The sea side is above x-axis, and the land side below. Given the position of each island in the sea, and given the distance of the coverage of the radar installation, your task is to write a program to find the minimal number of radar installations to cover all the islands. Note that the position of an island is represented by its x-y coordinates.

Figure A Sample Input of Radar Installations
Input

The input consists of several test cases. The first line of each case contains two integers n (1<=n<=1000) and d, where n is the number of islands in the sea and d is the distance of coverage of the radar installation. This is followed by n lines each containing two integers representing the coordinate of the position of each island. Then a blank line follows to separate the cases.

The input is terminated by a line containing pair of zeros
Output

For each test case output one line consisting of the test case number followed by the minimal number of radar installations needed. “-1” installation means no solution for that case.
Sample Input

3 2
1 2
-3 1
2 1

1 2
0 2

0 0
Sample Output

Case 1: 2
Case 2: 1

把海岸线看成是x轴,在大海中有若干岛屿,对应着坐标系上的坐标,在海岸线上可安置若干雷达,买个雷达可监控范围是以自身为中心,半径为d的圆,求最少安置雷达的数目可覆盖到全部岛屿
贪心策略比较难想到,可类比于区间求点,该题先找出对于每个岛屿来说能覆盖到的海岸线上的雷达的位置的左端点和右端点,雷达一定在该区间之内。再将所有岛屿对应的左端点非降序排序,贪心策略是雷达放置在第一个岛屿对应的右端点(选择当前情况下的最优解,将雷达放置右端可保证尽可能多覆盖到岛屿的数量),对于第二个岛屿,若左端点大于该雷达的坐标,则表示该雷达覆盖不到第二个岛屿,第二个岛屿应另外放置一个雷达;若左端点小于该雷达坐标,并且右端点也小于该雷达坐标,则更换雷达位置于第二个岛屿的右端点处;否则不用更换
这道题测试了很多次,花了很久时间,然后第二份代码运行超时了,还是不知道问题出在哪

//AC
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
typedef struct {
    double l, r;
}node;
node a[1000+10];
bool cmp(node a , node b){
    return a.l < b.l;
}
int main(){
    int n,d,i,cas = 0;
    while(scanf("%d%d",&n,&d) && (n || d)){  //当输入两个0时输入结束
        bool run = true;           
        for(i = 0;i < n;i++){
            int tx, ty;
            scanf("%d %d", &tx, &ty);
            if(abs(ty) > d){  //如果岛屿与海岸线的直线距离>d
                run = false;
            }
            a[i].l = (double)tx - sqrt((double)(d*d - ty*ty));  //能覆盖到该岛屿的雷达所在区间的左端  
            a[i].r = (double)tx + sqrt((double)(d*d - ty*ty));  //能覆盖到该岛屿的雷达所在区间的右端
        }
        if(!run){
            printf("Case %d: -1\n",++cas);
            continue;
        }
        sort(a,a+n,cmp);
        int ans = 1;
        double last = a[0].r;
        for(i = 1;i < n;i++){        //贪心策略
            if(a[i].l > last){
                ans ++;
                last = a[i].r;
            }
            else if (a[i].r < last)
                last = a[i].r;
        }
        printf("Case %d: %d\n",++cas,ans);
    }
    return 0;
}

//Time Limit Exceeded
#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;

/*struct Point{
    double x;   //注意不是int型,error
    double y;
    double rx,lx;   //分别是x轴上的圆心半径所在区间的左右范围,当点(x,y)在该圆边上时,此时dx = sqrt(r*r-y*y),lx = x-dx,rx = x+dx
};*/

struct Point{
    double rx,lx;   //分别是x轴上的圆心半径所在区间的左右范围,当点(x,y)在该圆边上时,此时dx = sqrt(r*r-y*y),lx = x-dx,rx = x+dx
};
bool compare(Point a,Point b){
    return a.lx<b.lx;
}

int main(){
    int n,d,i,count,flag,t = 0;     //Error 
    double r,x,y,dx;

    while(cin>>n>>d){       //岛屿数量与雷达的覆盖半径
        if(n == 0 && d == 0){  //(1<=n<=1000)
            break;
        }
        if(d<0){      //Attention
            flag = 1;
        }
        flag = 0;     //标志位
        t++;          //表示第t个测试实例
        vector<Point> p(n);
        for(i = 0;i < n;i++){     //岛屿的几何坐标
            cin>>x>>y;
            if(fabs(y) > d){       //Attention
                flag = 1;
            }
            dx = sqrt(d*d-y*y);    //changed
            p[i].lx = x-dx;
            p[i].rx = x+dx;
        }
        if(flag){
            cout<<"Case "<<t<<": -1"<<endl;
            continue;
        }
        sort(p.begin(),p.end(),compare);     //排序,按照x坐标非降序排列,x坐标相等就按照y坐标升序排列
        r = p[0].rx;                 //将第一个雷达位置放置在能覆盖到第一个岛屿的坐标范围的最右端
        count = 1;                   //计数所需雷达数量
        for(i = 1;i < n;i++){
            if(p[i].lx > r){         //此时雷达范围不能覆盖到下一个岛屿
                count++;
                r = p[i].rx;
            }
            else{
                if(p[i].rx < r){    //此时雷达位置应重置于该岛屿的最右端  
                    r = p[i].rx;
                }
            }
        }
        cout<<"Case "<<t<<": "<<count<<endl;

    }
    return 0;
}

DZY Loves Balls

HDU 5645 http://acm.hdu.edu.cn/showproblem.php?pid=5645

DZY loves playing balls.
He has n balls in a big box. On each ball there is an integer written.

One day he decides to pick two balls from the box. First he randomly picks a ball from the box, and names it A. Next, without putting A back into the box, he randomly picks another ball from the box, and names it B.

If the number written on A is strictly greater than the number on B, he will feel happy.

Now you are given the numbers on each ball. Please calculate the probability that he feels happy.

Input
First line contains t denoting the number of testcases.

t testcases follow. In each testcase, first line contains n, second line contains n space-separated positive integers ai, denoting the numbers on the balls.
(1≤t≤300,2≤n≤300,1≤ai≤300)

Output
For each testcase, output a real number with 6 decimal places.

Sample Input
2
3
1 2 3
3
100 100 100

Sample Output
0.500000
0.000000

有若干个上面有数字编号的球,抽出第一个球,记下该球上数字大小,不放回继续拿出第二个球,求第二个球上数字小于第一个数字的概率
贪心策略也就是数学算法,先将输入的数字按照非降序排序,如果没有相同的数字的话,那么已排序好的序列中所在位置就是比自身小的数字个数(从0计数),所以计算只要考虑到相同的数字的情况。排好序后,将某位置的数与前一个数比较,若是相同则继续与前一个数进行大小比较,相应计数减一,一直到不相等为止.可推论公式概率大小=每个数据比它小的数/(数据总数*(数据总数-1))之和
还要注意输出格式 printf(“%.6f\n”,s);

#include<stdio.h>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main(){
    int t,n,i,j,k;
    //scanf("%d",&t);     //测试样例个数
    cin>>t;
    double s;
    while(t--){
      cin>>n;
      //scanf("%d",&n);   //球的个数
      s = 0.0;
      k = 0;
      vector<int> a(n);

      for(i = 0;i < n;i++){
           cin>>a[i];
          //scanf("%d",&a[i]);
      }
      sort(a.begin(),a.end());  //非降序排序

      for(i = 1;i < n;i++){
          k = i;        //因为是非降序排序,若没有相等的数据则可认为小于该数据的数据的个数即元素在数组中位置
          j = i-1;
          while(a[j] == a[i] && j >= 0){  //考虑到出现相等数据的情况,从该数据往前判断,出现一个相等的元素则减一
            k--;
            j--;
          }
          s += k;
      }
      s = s*1.0/(n-1)/n;         //可推论公式概率大小=每个数据比它小的数/(数据总数*(数据总数-1))之和
      printf("%.6f\n",s);
    }
    return 0;
}

CA Loves Stick

HDU 5655 http://acm.hdu.edu.cn/showproblem.php?pid=5655

CA loves to play with sticks.
One day he receives four pieces of sticks, he wants to know these sticks can spell a quadrilateral.
(What is quadrilateral? Click here: https://en.wikipedia.org/wiki/Quadrilateral)

Input
First line contains T denoting the number of testcases.
T testcases follow. Each testcase contains four integers a,b,c,d in a line, denoting the length of sticks.
1≤T≤1000, 0≤a,b,c,d≤263−1

Output
For each testcase, if these sticks can spell a quadrilateral, output “Yes”; otherwise, output “No” (without the quotation marks).

Sample Input
2
1 1 1 1
1 1 9 2

Sample Output
Yes
No

有四根若干长度的木棍,判断能否组成四边形
判定方法:最长边大于其他三边之和
这里木棍长度数据范围很大,若用int型变量肯定会超出数据范围,所有这里用long long型,因为三个long long型变量相加也可能超出数据范围,所以这里现将四根木棍长度排序,然后利用最长边减去其中两条边大于第四条边来实现

//1.0 Error
#include <stdio.h>  
int main(){  
    long long a, b, c,d;  
    int z;  
    scanf("%d", &z);  
    while (z--){  
        scanf("%d%d%d%d",&a,&b,&c,&d);  
        printf("%s\n", a+b+d>c && a+c+d>b && b+c+d>a && b+c+a>d && a>0 && b>0 && c>0 && d>0? "Yes" : "No");    //可能会超出数据范围
    }  
    return 0;  
}
//AC 
#include<iostream>
#include<algorithm>
using namespace std;

int main(){  
    long long a[4]; 
    //int a[4];
    int t,i;  
    cin>>t;  
    while(t--){  
        for(i = 0;i < 4;i++){
            cin>>a[i];
        }
        sort(a,a+4);        //利用数组是为了方便排序,默认为升序排序
        //if(a[3]>0 && a[2]>0 && a[1]>0 && a[0]>0 && a[3]-a[2]-a[1]<a[0]){  不加括号就是错误结果  Attention!!!
        if(a[3]>0 && a[2]>0 && a[1]>0 && a[0]>0 && (a[3]-a[2]-a[1]<a[0])){
            cout<<"Yes"<<endl;
        }
        else{
            cout<<"No"<<endl;
        }
    }  
    return 0;  
}

猜你喜欢

转载自blog.csdn.net/a1128o/article/details/51959059