第十届蓝桥杯JavaB组--灵能传输
题目背景】 在游戏《星际争霸 II》中,高阶圣堂武士作为星灵的重要 AOE 单位,在 游戏的中后期发挥着重要的作用,其技能”灵能风暴“可以消耗大量的灵能对 一片区域内的敌军造成毁灭性的伤害。经常用于对抗人类的生化部队和虫族的 刺蛇飞龙等低血量单位。
【问题描述】 你控制着 n 名高阶圣堂武士,方便起见标为 1,2,··· ,n。每名高阶圣堂武士 需要一定的灵能来战斗,每个人有一个灵能值 ai 表示其拥有的灵能的多少(ai 非负表示这名高阶圣堂武士比在最佳状态下多余了 ai 点灵能,ai 为负则表示这 名高阶圣堂武士还需要 −ai 点灵能才能到达最佳战斗状态)。现在系统赋予了 你的高阶圣堂武士一个能力,传递灵能,每次你可以选择一个 i ∈ [2,n−1],若 ai ≥ 0 则其两旁的高阶圣堂武士,也就是 i−1、i + 1 这两名高阶圣堂武士会从 i 这名高阶圣堂武士这里各抽取 ai 点灵能;若 ai < 0 则其两旁的高阶圣堂武士, 也就是 i−1,i+1 这两名高阶圣堂武士会给 i 这名高阶圣堂武士 −ai 点灵能。形 式化来讲就是 ai−1+ = ai,ai+1+ = ai,ai−= 2ai。 灵能是非常高效的作战工具,同时也非常危险且不稳定,一位高阶圣堂 武士拥有的灵能过多或者过少都不好,定义一组高阶圣堂武士的不稳定度为 ,请你通过不限次数的传递灵能操作使得你控制的这一组高阶圣堂武 士的不稳定度最小。
【输入格式】
本题包含多组询问。输入的第一行包含一个正整数 T 表示询问组数。 接下来依次输入每一组询问。 每组询问的第一行包含一个正整数 n,表示高阶圣堂武士的数量。 接下来一行包含 n 个数 a1,a2,··· ,an。
试题 J: 灵能传输 15
第十届蓝桥杯大赛软件类省赛java大学B组
【输出格式】
输出 T 行。每行一个整数依次表示每组询问的答案。
【样例输入】
3
3
5 -2 3
4
0 0 0 0
3
1 2 3
【样例输出】
3
0
3
【样例说明】
对于第一组询问: 对 2 号高阶圣堂武士进行传输操作后 a1 = 3,a2 = 2,a3 = 1。答案为 3。 对于第二组询问:
这一组高阶圣堂武士拥有的灵能都正好可以让他们达到最佳战斗状态。
【样例输入】
3
4
-1 -2 -3 7
4
2 3 4 -8
5
-1 -1 6 -1 -1
【样例输出】
5
7
4
【样例输入】 见文件trans3.in。
【样例输出】 见文件trans3.ans。
【数据规模与约定】
刚刚考完,大概说下暴力的思路,不保证完全过,但是过样例没问题。题目的大致含义是,给出几组数据,然后经过变换再取每次变换得到的数组中的绝对值最大值,最后再从这一组变换得到的最大值中取最小者即为题解。题目规定只能取数组下标从[2,...,n-1]部分变换,然后由于有以下约定:
a[i-1]=a[i-1]+a[i];
a[i+1]=a[i+1]+a[i];
a[i]=-a[i];
每次以数组第i个位置向其两侧 i-1,i+1传递能量的时候,两边的能量会遵循上面式子的变化。例如上面给出的 {5 ,-2 ,3}。当我选择-2向两边传递能量时,因为-2<0,故此会从两边吸收能量,变换后对映到{5+(-2),-(-2),3+(-2)}. 即{3,2,1},同理,我们可以选择除数组头尾坐标以外的任何位置,进行上面的变化,并且把这一种情况记录在一个集合里面,然后每次取得到的数组中最大值与先前记录的最大值对比,如果比先前最大值小则替换先前的最大值。
代码:
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class 灵能传输 {
//用户装在每种询问的res值,以便于遍历结果
static int [] min;
//记录每种询问的能量数组组合情况。
static Set<String>set;
//记录全部情况的最小的不稳定度
static int res;
/**
* 将a数组组成一个字符串序列,记录在set中,用于排除重复的组合情况
* @param a 能量数组
* @return
*/
public static String getStr(int a[]){
StringBuilder sBuilder=new StringBuilder();
for(int i=0,len=a.length;i<len-1;i++){
sBuilder.append(a[i]+",");
}
sBuilder.append(a[a.length-1]);
return sBuilder.toString();
}
public static void dfs(int a[]) {
//得到组合字符串
String ar=getStr(a);
//如果当前的能量数组组合出现过,或者说res记录到最优的情况(没有比0还要小的绝对值了),则停止继续递归
if(set.contains(ar)||res==0) return;
//记录这种组合
set.add(ar);
int q[]=Arrays.copyOfRange(a, 0,a.length);
Arrays.sort(q);
//q[0]即为能量数组的最小的数,取绝对值并和该数组的最大值做比较,得到能量数组的不稳的度
int w=Math.max(Math.abs(q[0]),Math.abs(q[q.length-1]));
res=res>w?w:res;
for(int i=1,len=a.length-1;i<len;i++){
a[i-1]+=a[i];
a[i+1]+=a[i];
a[i]-=a[i]*2;
dfs(a);
}
}
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int n=scanner.nextInt();
min=new int[n];
for(int i=0;i<n;i++){
res=Integer.MAX_VALUE;
int num=scanner.nextInt();
int a[]=new int[num];
for(int k=0;k<num;k++){
a[k]=scanner.nextInt();
}
set=new HashSet<>();
dfs(a);
min[i]=res;
}
for(int i=0;i<min.length;i++){
System.out.println(min[i]);
}
}
}