算法训练#21:贪心的核心就是把事情简单化

95 阅读5分钟

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 24 天,点击查看活动详情

第一题

Scenes From a Memory

题目理解

给出一个整数nn,可以删掉它的任何一位,问最多可以删多少位使其不是质数 测试样例中的整数一定可以在删除若干位后不为质数

输入

输入整数tt,代表案例个数,1t10001\le t\le 1000
每个案例第一行输入1个整数kk——表示这个整数有多少位,1k501\le k\le 50 每个案例第二行输入1个整数nn10k1n10k10^{k-1}\le n\le 10^k 每一个样例中所有案例的kk的和不会超过10000

输出

每个案例输出22个整数——一个是删除后剩下的整数的位数,另一个是它本身

思路

这里其实我们有一个情况很好理解:若nn有一位数字不是素数,那么我们只需要删除到至剩下那一位就可以了。再推导一下:若不能达到只有一位的情况,那么我们只需要nn中找前后两位整数组合,若不是质数也可以达成我们的目的。那么问题来了:不会构成需要得出三位整数的情况吗?让我们来梳理一下:一个数只由若干个2、3、5、7组成,才能使第一种情况无法达成,那么这四个数两两组合,只有23、37和73是素数,是比较少的,那么我们可以拼一下样例里面没有这些情况,仅对剩下一位或者两位整数的情况做出判断即可。

代码

import java.util.Scanner;

public class Scenes_From_a_Memory {
    public static void main(String args[]) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        for (int i = 0; i < t; i++) {
            int k=sc.nextInt();
            String n=sc.next();
            char[] m=n.toCharArray();
            int res=n.length();
            String ans="";
            boolean f=false;
            //一位整数的情况进行判定
            for (int i1 = 0; i1 < m.length; i1++) {
                String x=String.valueOf(m[i1]);
                int y=Integer.parseInt(x);
                if(!isprime(y)) {
                    f = true;
                    ans=x;
                    break;
                }
            }
            if(f) {
                res=ans.length();
                System.out.println(res+"\n"+ans);
            }
            else{
                //两位整数的情况进行判定
                for(int j=0;j<m.length;j++) {
                    for (int i1 = j+1; i1 < m.length; i1++) {
                        StringBuffer x = new StringBuffer();
                        x.append(m[j]);
                        x.append(m[i1]);
                        int y = Integer.parseInt(String.valueOf(x));
                        if (!prime(y)) {
                            ans = String.valueOf(y);
                            break;
                        }
                    }
                }
                res=ans.length();
                System.out.println(res+"\n"+ans);
            }
        }
    }
    //判断一位整数是否为质数
    public static boolean isprime(int x){
        switch (x){
            case 2:
            case 3:
            case 5:
            case 7:
                return true;
            default:
                return false;
        }
    }
    //判断整数是否为质数
    public static boolean prime(int x){
        for(int i = (int) Math.sqrt(x);i<x;i++){
            if(x%i==0)
                return false;
        }
        return true;
    }
}

第二题

Problem - B - Codeforces

image.png

题目理解

有很多玩家想参与一个象棋比赛,其中他们对自己的比赛成绩有着下列两种期望的其中一种:

  1. 成为“不败战神”——没有一场是输掉的
  2. 赢至少一场

我们要找出是否存在一个满足所有玩家对自己的期望的结果。

输入

输入整数tt,代表案例个数,1t2001\le t\le 200
每个案例第一行输入1个整数nn2n502\le n\le 50。代表参赛选手人数 每个案例第一行输入一个字符串ss,其中ss中的第ii个字符若是1,则表明第ii个玩家对自己有着上面所描述的第一种期望

输出

每个案例的输出第一行是一个字符:“YES”或者“NO” 若为“YES”,下面则输出一个表示选手之间胜负关系的矩阵:
+ 在第ii行第jj列表示第ii名选手赢了第jj名选手
- 在第ii行第jj列表示第ii名选手输给了第jj名选手
= 在第ii行第jj列表示第ii名选手与第jj名选手战平
X 填入行数和列数相同的地方 若为“NO”,则不存在满足所有选手期望的胜负关系的矩阵,下面不输出任何内容

思路

要胜负关系满足所有要求,我们要去寻找规律:一旦出现需要那些不想输的人输掉的情况,矩阵就不可能存在。换言之,负场次只能出现在那些期望至少赢一场的人身上。我们根据这个思路就可以得出一个标准的赋值流程:先把期望一场不输的人的胜负关系全部赋予战平,然后去找那些想赢至少一场的人两两组合(这里要求至少赢一场的人数是奇数也没有关系)各胜对方一场,再把剩余的场次赋予战平,那么答案的矩阵就出来了。然后剩下的就是要注意一下特殊的情况判定了。

代码

import java.util.Scanner;

public class Chess_Tournament {
    public static void main(String args[]) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        for (int i = 0; i < t; i++) {
            int n=sc.nextInt();
            String s=sc.next();
            if(s.replaceAll("1","").length()<3&&s.contains("2")){//特殊情况直接判
                System.out.println("NO");
                continue;
            }
            char [][] x=new char[n][n];//答案矩阵初始化
            for(int j=0;j<n;j++) {
                for (int k = 0; k < n; k++) {
                    x[j][k]='0';
                }
            }
            for(int j=0;j<n;j++){
                x[j][j]='X';
            }
            char[] a=s.toCharArray();
            char w='=';
            //赋予战平
            for(int j=0;j<n;j++){
                switch (a[j]){
                    case '1':
                        for(int k=0;k<n;k++){
                            if(k!=j) {
                                x[j][k] = w;
                                x[k][j] = w;
                            }
                        }
                        break;

                }
            }
            if(s.contains("2")) {//找两个要求不是不败的人出来各胜对方一场
                boolean f = true;
                for (int j = 0; j < n; j++) {
                    switch (a[j]) {
                        case '2':
                            for (int k = 0; k < n; k++) {
                            //这里加上这层判断就是怕会赋值错误,一定要找前面没有被赋值的人,保证矩阵符合要求
                                if (x[j][k] == '0') {
                                    x[j][k] = '+';
                                    x[k][j] = '-';
                                    break;
                                }
                            }
                    }
                }
            }
            //把剩下的赋值完毕
            for(int j=0;j<n;j++) {
                for (int k = 0; k < n; k++) {
                    if(x[j][k]=='0'){
                        x[j][k]=w;
                    }
                }
            }
            //输出
            System.out.println("YES");
            for(int j=0;j<n;j++){
                for(int k=0;k<n;k++){
                    System.out.print(x[j][k]);
                }
                System.out.println();
            }
        }
    }
}