Java 蓝桥杯 完美的代价

本文介绍了一种解决如何通过最少交换次数将非回文字符串转化为回文字符串的方法。首先,通过判断字符串中奇数次出现的字母数量来确定是否能构成回文,如果奇数个数大于1则不可能。接着,对于可以构成回文的字符串,通过计算首字母在字符串中最后一次出现的位置,并进行相应操作,确定所需的交换次数。提供的代码实现了这一逻辑,并给出了具体的解题思路和流程图。

问题描述

回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
  交换的定义是:交换两个相邻的字符
  例如mamad
  第一次交换 ad : mamda
  第二次交换 md : madma
  第三次交换 ma : madam (回文!完美!)

输入
输入描述:
  第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
  第二行是一个字符串,长度为N.只包含小写字母
输入样例:
5
mamad

输出

输出描述:
  如果可能,输出最少的交换次数。
  否则输出Impossible
输出样例:
3

HINT:时间限制:1.0s 内存限制:512.0MB

解题思路

首先要判断输入的是不是回文数,就先判断每个字母出现的次数以及奇数字母的个数,若奇数次数的字母个数大于1的话就不能构成回文数,在判断交换次数时还要注意如果是1位或者2位字符串的话就直接返回0,因为1,2位的就是回文数不用交换,接下来就是判断每次首字母在后面出现的次数了,如果首字母只有一次的话就把他放到中间,其余的再进行循环运算,就相当于在中间的两边加字符

代码

import java.util.Locale;
import java.util.Scanner;
import java.util.regex.Pattern;

public class Main {

    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        int m=scanner.nextInt();
        String n=scanner.next();
        if (panduan(n)){
            System.out.println(cishu(n));
        }else {
            System.out.println("Impossible");
        }
    }
    public static boolean panduan(String n){
        //判断是否构成回文数 就是判断字母出现为奇数次数的个数
        boolean panduan=true;
        int [] num=new int[26];
        int geshu=0;//记录奇数次的个数
        for (int i=0;i<n.length();i++){
            num[n.charAt(i)-'a']++;//得到每个字母对应的数值
        }
        //统计奇数次字母出现的个数
        for (int i=0;i< num.length;i++){
            if (num[i]%2==1){
                geshu++;
            }
        }
        if (geshu>1){
            panduan=false;//若大于1 则不能形成回文数
        }
        return panduan;
    }
    //如果为回文数 则判断交换次数
    public static  int cishu(String n){
        int cishu=0;
        if(n.length()==1 || n.length()==2){//只有1位和2位的字符串 就是回文数 返回0次
            return 0;
        }
        cishu=n.lastIndexOf(n.charAt(0));//每次首字母最后出现位置的索引
        if (cishu==0){
            return n.length()/2 + cishu(n.substring(1,n.length()));//如果首字母只出现了首字母放到中间 
            //substring的作用为截取第1位到最后一位的字符串。
        }else {
            StringBuilder stringBuilder=new StringBuilder(n);//如果不为1次的话移动的次数就是 长度-cishu-1 然后再删除计算过的。
            stringBuilder.deleteCharAt(cishu);//删除已经计算过的
            //deleteCharAt为移除此位置的字符
            stringBuilder.deleteCharAt(0);
            return n.length()-cishu-1 + cishu(stringBuilder.toString());
        }
    }
}

流程图

Created with Raphaël 2.3.0 开始 输入字符串的长度m以及字符串n 定义panduan为真,一个26位的数组,用geshu记录奇数次字符的个数 依次计算每个字母对应的数值 奇数次字符的个数大于1 panduan为假 定义cishu来接收字母的索引 如果只有一个或者两个字符 返回0 结束 计算每次首字母在后面出现位置的索引 如果只出现了一次 循环计算需要的次数 构成回文数 输出需要的次数 输出Impossible 建立一个stringBuilder来简便操作字符串 删除已经计算过的和首位字符 重新计算需要的次数 yes yes no yes no yes no
### 关于蓝桥杯竞赛中的“景区导游问题” #### 问题描述 假设有一个旅游景点,游客可以选择不同的路径游览各个景点。每条路径都有一定的距离或者权重,目标是最优地规划一条路线使得总路程最短或满足某些特定条件。 以下是基于动态规划和图论算法的一种解决方案及其详细解析: --- #### 实现思路 1. **建模** 将景区视为一张无向加权图 \( G(V, E) \),其中节点代表各景点,边上的权重表示两景点之间的距离。通过输入数据构建邻接矩阵或其他形式的存储结构来保存这些关系[^1]。 2. **状态定义** 使用动态规划求解旅行商问题(TSP)的一个变种版本——即找到经过所有指定点并返回起点的最佳顺序。设 `dp[S][i]` 表示当前访问集合为 S 的情况下到达第 i 个地点所需的最小代价。 3. **转移方程** 对于每一个可能的状态更新 dp 数组: \[ dp[S][j]=\min(dp[S-\{j}][k]+dist[k][j]) \] 这里 k 属于未被标记过的其他顶点集;而 dist[][] 存储任意两点间实际测量得到的距离值[^2]。 4. **初始化与边界条件设置** 初始时仅考虑从源节点出发的情况,则有: \[ dp[\text{{source}}][s]=0,\quad s=\{\text{{source}}\} \] 5. **最终结果获取** 遍历整个状态空间找出全局最优解,并回溯记录具体路径信息以便后续打印输出[^3]。 --- #### 参考代码实现 下面提供了一个简单的 Java 版本程序框架用于解决上述提到类型的题目需求: ```java import java.util.*; public class ScenicGuide { private static final int INF = Integer.MAX_VALUE; public static void tsp(int n, int start, int[][] graph){ // 动态规划数组 dp[mask][i], mask 是位掩码表示已访问的城市组合 long[][] dp = new long[1<<n][n]; for(int mask=0;mask<(1<<n);mask++) Arrays.fill(dp[mask],INF); dp[(1<<start)][start]=0; for(int mask=1;mask<(1<<n);mask++){ if((mask&(1<<start))==0) continue;// must include the starting city for(int u=0;u<n;u++){ if( ((mask>>u)&1)==0 ) continue; for(int v=0;v<n;v++){ if(v==u || ((mask>>v)&1)==0) continue; dp[mask][u]=Math.min( dp[mask][u], dp[mask^(1<<u)][v]+graph[v][u]); } } } // Find minimum cost to visit all cities and come back to 'start' long answer = INF; int fullMask=(1<<n)-1; for(int lastCity=0;lastCity<n;lastCity++) answer=Math.min(answer,dp[fullMask][lastCity]+graph[lastCity][start]); System.out.println("Minimum Cost:"+answer); } public static void main(String[] args){ Scanner sc=new Scanner(System.in); int N=sc.nextInt(); // Number of scenic spots int M=sc.nextInt(); // Number of roads between them int[][] adjacencyMatrix=new int[N][N]; for(int i=0;i<N;i++)Arrays.fill(adjacencyMatrix[i],INF); for(int i=0;i<M;i++){ int a=sc.nextInt()-1,b=sc.nextInt()-1,dist=sc.nextInt(); adjacencyMatrix[a][b]=adjacencyMatrix[b][a]=dist; } tsp(N,sc.nextInt()-1,adjacencyMatrix); } } ``` --- #### 注意事项 - 输入的数据规模较大时需注意效率优化。 - 如果地图存在孤立子图则应单独处理以免影响整体计算逻辑准确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

future furuer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值