一、问题 1433: [蓝桥杯][2013年第四届真题]危险系数
时间限制: 1Sec 内存限制: 128MB 提交: 726 解决: 258
题目描述
问题描述
抗日战争时期,冀中平原的地道战曾发挥重要作用。
地道的多个站点间有通道连接,形成了庞大的网络。但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系。
我们来定义一个危险系数DF(x,y):
对于两个站点x和y (x != y), 如果能找到一个站点z,当z被敌人破坏后,x和y不连通,那么我们称z为关于x,y的关键点。相应的,对于任意一对站点x和y,危险系数DF(x,y)就表示为这两点之间的关键点个数。
本题的任务是:已知网络结构,求两站点之间的危险系数。
输入
输入数据第一行包含2个整数n(2 < = n < = 1000), m(0 < = m < = 2000),分别代表站点数,通道数;
接下来m行,每行两个整数 u,v (1 < = u, v < = n; u != v)代表一条通道;
最后1行,两个数u,v,代表询问两点之间的危险系数DF(u, v)。
输出
一个整数,如果询问的两点不连通则输出-1.
样例输入
7 6
1 3
2 3
3 4
3 5
4 5
5 6
1 6
样例输出
2
思路:图 用矩阵表示,进行bfs,用cnt记录每个点被访问的次数
代码来自别人。我的代码错在 一开始没有考虑全面,导致后期添加记录每个点被访问的次数困难,这也是我的一个短板,但作为图的深搜,记录不同步骤,还是有参考意义的。
正确代码:
import java.util.ArrayList;
import java.util.Scanner;
public class 危险系数 {
static boolean[] visited = null; // 用于记录该点是否为关键点
static int[] cnt = null; // 用于统计该点已经走过几次
static int[] way = null; // 用于记录路径
static int ans = 0; // 路径总数
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); // 站点数
int m = sc.nextInt(); // 通道数
// 初始化三个数组
visited = new boolean[n];
way = new int[n];
cnt = new int[n];
// 用于记录通道
ArrayList<Integer>[] stand = new ArrayList[n];
for(int i = 0; i < n ; i++){
stand[i] = new ArrayList<Integer>();
}
// 得到通道
for(int i = 0 ; i < m; i++){
int u = sc.nextInt() - 1;
int v = sc.nextInt() - 1;
stand[u].add(new Integer(v));
stand[v].add(new Integer(u));
}
int a = sc.nextInt() - 1;
int b = sc.nextInt() - 1;
// 遍历通道
DFS(a, b, stand, 0);
// 获取结果
System.out.println(GetResult());
}
/**
* 深度优先搜索通道
* @param start 当前节点
* @param end 末节点
* @param stand 通道集合
* @param k 当前是第几步
*/
public static void DFS(int start, int end, ArrayList<Integer>[] stand, int k){
visited[start] = true; // 标记当前已经走过
way[k] = start; // 第 k 步走了start这个点
if(start == end){ // 当start等于结束这个点的时候,即找到了一条路径
ans++; // 路径数目加一
// 一共走了k步,注意:i < k 即没有把最后end这个点算在里面,最后结果不要算end这个点
for(int i = 0; i < k; i++){
cnt[way[i]]++; // 这条路径走过的点次数都加一
}
return;
}
// 深搜
for(int i = 0; i < stand[start].size(); i++){
int temp = stand[start].get(i).intValue();
if(!visited[temp]){
DFS(temp, end, stand, k + 1);
visited[temp] = false; // 还原点
}
}
}
public static int GetResult(){
int sum = 0;;
for(int i = 0; i < cnt.length; i++){
if(cnt[i] == ans){ // 点出现的次数和路径个数相同,既每次都出现这个点,这个点为必须点
sum++;
}
}
return sum - 1; // 减去第一个点
}
}
我的错误代码:
package day5;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Scanner;
public class t1433 {
static HashMap<String, Boolean> hms=new HashMap<String, Boolean>();
static int []vis;
static int []count;
static int m;
static int n;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
m=sc.nextInt();
n=sc.nextInt();
vis=new int[m];
count=new int[m];
int [][]num=new int[m][n];
for(int i=0;i<n;i++){
int x=sc.nextInt();
int y=sc.nextInt();
num[x-1][y-1]=1;
num[y-1][x-1]=1;
}
// System.out.println("!!");
int c1=sc.nextInt();
int c2=sc.nextInt();
bfs(num, c1-1, c1-1, c2-1, "");
if(hms.size()==0){
System.out.println("-1");
}else{
// System.out.println(hms.size());
for(int i=0;i<m;i++){
System.out.print(count[i]+" ");
}
count[c1-1]=-1;count[c2-1]=-1;
Arrays.sort(count);
System.out.println();
int max_num=1;
for(int i=m-2;i>=0;i--){
if(count[i]==count[m-1]){
max_num++;
}
}
System.out.println(max_num);
}
}
public static void bfs(int [][]num,int x,int y,int c2,String luj){
// System.out.println(x+" "+y+" "+c2+" "+luj);
if(y==c2&&num[x][y]==1){
if(!hms.containsKey(luj)){
hms.put(luj, true);
// System.out.println(luj);
}
// System.out.println("ok!");
return;
}
for(int i=y;i<num[0].length;i++){
if(num[x][i]==1&&vis[i]==0){
String s=luj+" "+x+" "+i;
if(i==c2&&num[x][i]==1){
if(!hms.containsKey(luj)){
System.out.println(s);
System.out.println("ok!");
hms.put(luj, true);
// vis[i]=1;
}
// System.out.println("ok!");
// return;
}
}
}
vis[y]=1;
count[y]++;
for(int i=y;i<num[0].length;i++){
if(num[x][i]==1&&vis[i]==0){
String s=luj+" "+x+" "+i;
vis[i]=1;
count[i]++;
bfs(num, i, 0, c2, s);
vis[i]=0;
}
}
}
// public static void tongji(String s1,String s2){//统计两个字符串中,字符重复个数
// String []ss1=s1.split(" ");
// String []ss2=s2.split(" ");
// int []num=new int [m];
// for(int i=0;i<ss1.length;i++){
// for(int j=0;j<ss2.length;i++){
// if(ss1[i].equals(ss2[j])){
// num[Integer.parseInt(ss1[i])]++;
// }
// }
// }
// for(int i=0;i<m;i++){
// System.out.print(num[i]+" ");
// }
// syso
//
// }
}
二、愤怒小鸟
描述
X星球愤怒的小鸟喜欢撞火车!
一根平直的铁轨上两火车间相距 1000 米
两火车 (不妨称A和B) 以时速 10米/秒 相对行驶。
愤怒的小鸟从A车出发,时速50米/秒,撞向B车,
然后返回去撞A车,再返回去撞B车,如此往复…
两火车在相距1米处停车。
问:这期间愤怒的小鸟撞 B 车多少次?
注意:需要提交的是一个整数(表示撞B车的次数),不要填写任何其它内容。
输入
没有输入。
输出
package day3;
public class t1 {
public static void main(String[] args) { //PS:相对行驶,即面对面行驶
double a=0,b=1000;
while(b>=1){
//计算的d是碰撞之后,ab之间的距离
b = b- 20 * (b/60); //由a向b行驶,20是指两个火车速度和,60是鸟的速度+b车速度
System.err.println(b+" "+1);
b = b - 20 * (b/60); //由b向a行驶,20是指两个火车速度和,60是鸟的速度+a车速度
System.err.println(b+" "+2);
a++;
}
System.out.println(a);
}
}
二、反幻方
描述
我国古籍很早就记载着
2 9 4
7 5 3
6 1 8
这是一个三阶幻方。每行每列以及对角线上的数字相加都相等。
下面考虑一个相反的问题。
可不可以用 1~9 的数字填入九宫格。
使得:每行每列每个对角线上的数字和都互不相等呢?
这应该能做到。
比如:
9 1 2
8 4 3
7 5 6
你的任务是搜索所有的三阶反幻方。并统计出一共有多少种。
旋转或镜像算同一种。
比如:
9 1 2
8 4 3
7 5 6
7 8 9
5 4 1
6 3 2
2 1 9
3 4 8
6 5 7
等都算作同一种情况。
请提交三阶反幻方一共多少种。这是一个整数,不要填写任何多余内容。
输入
没有输入。
输出
控制台输出答案为一个整数。
思路:1-9全排列,判断是不是符合条件,利用HashSet存储,便于判断是反幻方,每个情况都是八种,再除以8
package day3;
import java.util.HashSet;
public class t2 {
static int count = 0;
public static void main(String[] args) {
int []num={1,2,3,4,5,6,7,8,9};
qpl(num, 0);
System.out.println(count/8);
}
public static void qpl(int []num,int i){
if(i==num.length){
// for(int t=0;t<num.length;t++){
// System.out.print(num[t]+" ");
// }
// System.out.println();
jud(num);
}else{
for(int t=i;t<num.length;t++){
swap(num, t, i);
qpl(num, i+1);
swap(num, t, i);
}
}
}
public static void jud(int []A){
int[] sum = new int[8];
sum[0] = A[0] + A[1] + A[2];
sum[1] = A[3] + A[4] + A[5];
sum[2] = A[6] + A[7] + A[8];
sum[3] = A[0] + A[3] + A[6];
sum[4] = A[1] + A[4] + A[7];
sum[5] = A[2] + A[5] + A[8];
sum[6] = A[0] + A[4] + A[8];
sum[7] = A[2] + A[4] + A[6];
HashSet<Integer> set = new HashSet<Integer>();
for(int i = 0;i < 8;i++)
set.add(sum[i]);
if(set.size() == 8)
count++;
}
public static void swap(int []num,int x,int y){
int t=num[x];
num[x]=num[y];
num[y]=t;
}
}
三、打靶
描述
小明参加X星球的打靶比赛。
比赛使用电子感应计分系统。其中有一局,小明得了96分。
这局小明共打了6发子弹,没有脱靶。
但望远镜看过去,只有3个弹孔。
显然,有些子弹准确地穿过了前边的弹孔。
不同环数得分是这样设置的:
1,2,3,5,10,20,25,50
那么小明的6发子弹得分都是多少呢?有哪些可能情况呢?
下面的程序解决了这个问题。
仔细阅读分析代码,填写划线部分缺失的内容。
输入
没有输入。
输出
思路: 这应该叫递归???对于填空处,如果这里打了孔,对于递归后,孔数就要减一
package day3;
public class t3
{
/**
* ta是判分
* da是
* k是
* ho 初始时3,即弹孔数
* bu 初始时6,即发射数
* sc初始是96,即得分数
* */
static void f(int[] ta, int[] da, int k, int ho, int bu, int sc)
{
if(ho<0 || bu<0 || sc<0) return;
if(k==ta.length){
if(ho>0 || bu>0 || sc>0) return;
for(int i=0; i<da.length; i++){
for(int j=0; j<da[i]; j++)
System.out.print(ta[i] + "*");
}
System.out.println();
return;
}
for(int i=0; i<=bu; i++){
da[k] = i;
// System.out.println(k+" "+da[k]);
f(ta, da, k+1, ho - (i == 0 ? 0 : 1), bu-i, sc-ta[k]*i); // 填空位置
}
da[k] = 0;
}
public static void main(String[] args)
{
int[] ta = {1,2,3,5,10,20,25,50};
int[] da = new int[8];
f(ta, da, 0, 3, 6, 96);
}
}