1. 世纪末的星期
Calendar类需要注意的两个点:
(1)Calenda.MONTH要比实际月份小1。
(2)Calendar.DAY_OF_WEEK,1代表星期天。
import java.util.Calendar;
import java.util.Scanner;
public class Main
{
public static void main(String args[])
{
int y = 2000;
Calendar cal = Calendar.getInstance();
cal.set(Calendar.MONTH, 11);
cal.set(Calendar.DAY_OF_MONTH, 31);
while(true)
{
int year = y+99;
cal.set(Calendar.YEAR, year);
if(cal.get(Calendar.DAY_OF_WEEK)==1)
{
System.out.println(year);break;
}
y += 100;
}
}
}
答案:2299
2. 振兴中华
搜索,两条树枝,往右和往下
public class Main
{
static int BoundX = 3;
static int BoundY = 4;
static int cnt=0;
public static void main(String args[])
{
f(0,0);
System.out.println(cnt);
}
static void f(int x,int y)
{
if(x>BoundX || y>BoundY) return ;
if(x==BoundX && y==BoundY) { cnt++; return; }
f(x+1,y); //往下
f(x,y+1); //往右
}
}
答案:35
3. 梅森素数
这道题考的是快速幂乘
比如a的11次幂,11二进制可写为1011
那么就是a^1 * a^2 * a^8
那么就可以不停的幂乘,然后二进制位是1的时候就乘以此时幂乘的结果
import java.math.BigInteger;;
public class Main
{
public static void main(String args[])
{
BigInteger a = new BigInteger("2");
int k = 11213;
BigInteger ans = Mi(a,k);
ans = ans.subtract(BigInteger.ONE);
String str = ans.toString();
str = str.substring(str.length()-100,str.length());
System.out.println(str);
}
static BigInteger Mi(BigInteger a,int b) //幂乘 a^b
{
BigInteger ret = new BigInteger("1");
while(b>0)
{
if((b&1)==1) ret = ret.multiply(a); //二进制位为1时,乘上此时的a
a = a.multiply(a); //a自身幂乘,翻倍
b = b>>1;
}
return ret;
}
}
答案:8586718527586602439602335283513944980064327030278104224144971883680541689784796267391476087696392191
4. 颠倒的价牌
本题枚举+判断即可。
主要操作在数的翻转上
可以将数字转成String,再转成char数组,一位一位判断,首末为0,则不能倒过来,某位为3,4,7的一种也不能倒过来,某位是6,9,转为9,6.
最后再将char数组转成String,利用StringBuffer的reverse()函数翻转一下。
public class Main
{
// 能倒过来的数字有 1 2 5 6 8 9 0 , 不能倒过来的有3 4 7
// 倒过来为 1 2 5 9 8 6 0 ,也就是只能6,9倒过来
public static void main(String args[])
{
for(int x=1000; x<=9999; x++)
{
for(int y=x+1; y<=9999; y++)
{
int rx = reverse(x);
int ry = reverse(y);
if(rx==0||ry==0) continue;
int dx = rx-x;
int dy = ry-y;
if(dy>-300 && dy<-200 && dx>800 && dx<900 && (dx+dy)==558)
{
System.out.println(x+" "+y);
}
}
}
}
static int reverse(int num)
{
String s = String.valueOf(num);
char[] ch = s.toCharArray();
if(ch[0]=='0'||ch[3]=='0') return 0; //首位末尾不能为0
int temp=num;
int cnt=3;
while(temp>0)
{
int mod = temp%10;
if(mod==3||mod==4||mod==7) return 0; // 3,4,7不能倒
if(mod==6) ch[cnt] += 3;
else if(mod==9) ch[cnt] -= 3;
temp = temp/10;
cnt--;
}
StringBuffer buf = new StringBuffer(new String(ch));
buf.reverse(); //翻转一下
return Integer.parseInt(buf.toString());
}
}
输出:
1061 9088
2062 9088
5065 9088
6069 9088
8068 9088
9066 9088
所以赔钱的价格为9088。
5. 三部排序
答案:p++
6. 逆波兰表达式
这个可以去看下数据结果的前缀、中缀、后缀表达式。
填空位置的上一句 int[] v1 = evaluate(x.substring(1)); 会在遇到第一个不是运算符的数字时返回,那v2应该接下去处理。
答案:evaluate(x.substring(1+v1[1]))
7. 错误票据
这道题主要考数据的处理。首先输入每行的数据长度也即票据号个数不同,这点用String类即可处理:用String接收一行数据,然后用split()函数分割数据,需注意的是分割是以若干个空格,split(regex)中的regex应该为"\s+"(这个可以去百度Java的正则表达式匹配)。
然后是存储,因为不知道票据总个数,所以用List存储比较好,把分割出来的字符串转成Integer,add()到List中。
处理完输入,对List排序(用Collections.sort()即可),然后找断号和重号即可。
import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
public class Main
{
static int N;
public static void main(String args[])
{
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
sc.nextLine(); //先吃掉一个换行符
List<Integer> ls = new ArrayList<Integer>();
String str;
String[] sp;
for(int i=0;i<N;i++)
{
str = sc.nextLine();
sp = str.split("\\s+"); //以若干个空格分割
for(int j=0;j<sp.length;j++)
{
ls.add(Integer.parseInt(sp[j]));
}
}
//输入处理完
//排序
Collections.sort(ls);
//遍历找断号和重号
int m=0,n=0;
for(int i=1;i<ls.size();i++)
{
if(ls.get(i)-ls.get(i-1)==2) m = ls.get(i)-1; //断号
else if(ls.get(i)-ls.get(i-1)==0) n = ls.get(i); //重号
}
System.out.println(m+" "+n);
}
}
8. 带分数
这道题可以先对1~9全排列,然后对排列的每种情况做判断,从第一个数的位数为1开始,到第一个数的位数与N的位数相同。
import java.util.Scanner;
public class Main
{
static int N;
static int Len;
static int cnt=0;
public static void main(String args[])
{
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
Len = getLen(N);
char[] a = new char[] {'1','2','3','4','5','6','7','8','9'};
mySort(a,0);
System.out.println(cnt);
}
static int getLen(int n)
{
int ret=0;
while(n>0)
{
n=n/10;
ret++;
}
return ret;
}
static void mySort(char a[],int k)//1~9全排列
{
if(k==9) {
f(a); return ;
}
for(int i=k;i<9;i++)
{
{char t=a[i];a[i]=a[k];a[k]=t;}
mySort(a,k+1);
{char t=a[i];a[i]=a[k];a[k]=t;}
}
}
static void f(char ch[])
{
String str = new String(ch);
for(int l=1;l<=Len;l++) //第一个数的长度
{
int half=(9-l)/2;
String s1 = str.substring(0, l);//取第一个数
int n1 = Integer.parseInt(s1);
for(int h=half;h<=half+Len/2;h++) //第二个数的长度
{
String s2 = str.substring(l,l+h);//取第二个数
String s3 = str.substring(l+h,9);//取第三个数
int n2 = Integer.parseInt(s2);
int n3 = Integer.parseInt(s3);
double d = n2*1.0/n3;
if(n1+d==N) //判断
{
cnt++;
}
}
}
}
}
9. 剪格子
深搜+减枝
int[] dx = {-1,1,0,0};
int[] dy = {0,0,-1,1};
根据 x+dx[i] 和 y+dy[i] 控制往上下左右四个方向搜索。
然后记录走过格子的个数cnt,以及走过格子的数字和sum。
如果sum>数字和的一半,不用再继续搜了,减枝。
如果sum==数字和的一半,找到符合的剪法了,判断左上角包含的格子是不是最小的,不断更新min的值。
import java.util.Scanner;
public class Main
{
static int M,N;
static int[][] a;
static boolean[][] vis; //标记走过的格子
static int Half=0;
static int[] dx = {-1,1,0,0}; //上下左右走 x,y坐标的变动
static int[] dy = {0,0,-1,1};
static int min=100;
public static void main(String args[])
{
Scanner sc = new Scanner(System.in);
M = sc.nextInt();
N = sc.nextInt();
a = new int[N][M];
vis = new boolean[N][M];
int sum = 0;
for(int i=0;i<N;i++)
for(int j=0;j<M;j++) {
a[i][j]=sc.nextInt();
sum+=a[i][j];
}
sc.close();
if(sum%2==1) { //无法分割
System.out.println("0"); return;
}
Half = sum/2;
f(0,0,0,0);
System.out.println(min);
}
static void f(int x,int y,int sum,int cnt) //(x,y)是当前格子的坐标,sum是走过格子的数字和,cnt是走过格子的个数
{
if(sum>Half) return;
if(sum==Half) {
min = (cnt<min)?cnt:min;
return ;
}
vis[x][y]=true;
for(int i=0;i<4;i++)
{
int nx = x+dx[i];
int ny = y+dy[i];
if(nx<0||nx>=N||ny<0||ny>=M||vis[nx][ny]==true) continue;
f(nx,ny,sum+a[x][y],cnt+1);
}
vis[x][y]=false;
}
}
10.大臣的旅费
这道题考点是求 “ 图的直径 “
图的直径的求法,就是任意确定一个点,找距离该点的最远点,记这个最远点为temp,再找temp的距离最远点,temp到它最远点的距离就是图的直径。
由于本题说了任意两个城市都能到达,且高速路的条数为n-1条,那这个图必然是主树。该图内肯定不会有闭环,那么处理起来就方便了,搜索时就只要保证下个节点不是当前节点的前一个就行,也就是当前为now,下个为next,前一个为from,只要next!=from,next这个点就可以往下搜。
import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;
public class Main
{
static class Node
{
int id;
int weigth;
public Node(int id,int weigth)
{
this.id=id;
this.weigth=weigth;
}
}
static int n;
static List<Node>[] ls ;
static int max=0;
static int temp;
public static void main(String args[])
{
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
ls = new List[n+1];
for(int i=0;i<=n;i++)
ls[i] = new ArrayList<Node>();
for(int i=1;i<n;i++)
{
int f = sc.nextInt();
int t = sc.nextInt();
int w = sc.nextInt();
ls[f].add(new Node(t,w));
ls[t].add(new Node(f,w));
}
f(1,0,0); //求距离1的最远点,得到temp
f(temp,0,0); //求距离temp的最远点,结束后的max为直径
System.out.println(max*10+max*(max+1)/2);
}
static void f(int index,int from,int sum) //一个点到距离它最远点,temp在结束函数调用后为那个最远点,max为它们之间的距离
{
boolean flag=true; //假设一进来认为该节点为叶子节点,就是不能往下搜了
for(int x=0;x<ls[index].size();x++)
{
int next = ls[index].get(x).id;
if(next==from) continue;
flag = false; //还能往下搜,不是叶子节点,改变标记
f(next,index,sum+ls[index].get(x).weigth);
}
if(flag) //确定是叶子节点
if(sum>max) { max=sum; temp=index;}
}
}
这代码格式简直逼死强迫症,自己加Tab加的无语,如果有知道怎么调的,麻烦评论里教我下,谢谢~