答案为28
答案为6
package Contest_2015;
/**
* 答案为6
* @author Admin
*
*/
public class 立方变身 {
public static void main(String[] args) {
long count = 0;
for (int i = 1; i <= 50000; i++) {
long num = (long) Math.pow(i, 3);
long temp = function(num);
if(temp == i){
count++;
System.out.println(i);
}
}
System.out.println(count+"个");
}
// 按位累加
private static long function(long num){
int sum = 0;
while(num!=0){
sum += num%10;
num/=10;
}
return sum;
}
}
DFS全排列,答案为1085
package Contest_2015;
/**
* abcd+efgb=efcbh
*
* @author Admin
*
*/
public class 三羊献瑞 {
static int[] visit;
static int[] comb;
public static void main(String[] args) {
// TODO Auto-generated method stub
visit = new int[10];
comb = new int[8];
dfs(0);
}
private static void dfs(int depth) {
if (depth == 8) {
if (check()) {
if(comb[4] == 0)
return;
System.out.printf("%d%d%d%d\n", comb[4], comb[5], comb[6], comb[1]);
// for (int i = 0; i < comb.length; i++) {
// System.out.println(comb[i]);
// }
}
return;
}
for (int i = 0; i <= 9; i++) {
if (visit[i] == 0) {
comb[depth] = i;
visit[i] = 1;
dfs(depth + 1);
visit[i] = 0;// go back
}
}
}
// abcd+efgb=efcbh
private static boolean check() {
int a = comb[0];
int b = comb[1];
int c = comb[2];
int d = comb[3];
int e = comb[4];
int f = comb[5];
int g = comb[6];
int h = comb[7];
int abcd = a * 1000 + b * 100 + c * 10 + d;
int efgb = e * 1000 + f * 100 + g * 10 + b;
int efcbh = e * 10000 + f * 1000 + c * 100 + b * 10 + h;
if (abcd + efgb == efcbh)
return true;
return false;
}
}
package Contest_2015;
import java.util.Vector;
public class 循环节长度 {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(f(13, 11));
}
public static int f(int n, int m) {
n = n % m;
Vector v = new Vector();
for (;;) {
v.add(n);
n *= 10;
n = n % m;
if (n == 0)
return 0;
if (v.indexOf(n) >= 0)
return v.size(); // 填空
}
}
}
DFS全排列,填空部分为“回溯”操作
package Contest_2015;
public class 九数组分数 {
public static void test(int[] x) {
int a = x[0] * 1000 + x[1] * 100 + x[2] * 10 + x[3];
int b = x[4] * 10000 + x[5] * 1000 + x[6] * 100 + x[7] * 10 + x[8];
if (a * 3 == b)
System.out.println(a + " " + b);
}
// 全排列
public static void f(int[] x, int k) {
if (k >= x.length) {
test(x);
return;
}
for (int i = k; i < x.length; i++) {
{
int t = x[k];
x[k] = x[i];
x[i] = t;
}
f(x, k + 1);
{
int t = x[k];
x[k] = x[i];
x[i] = t;
} // 填空
}
}
public static void main(String[] args) {
int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
f(x, 0);
}
}
package Contest_2015;
/**
*
* 牌型种数
*
* 小明被劫持到X赌城,被迫与其他3人玩牌。 一副扑克牌(去掉大小王牌,共52张),均匀发给4个人,每个人13张。 这时,小明脑子里突然冒出一个问题:
* 如果不考虑花色,只考虑点数,也不考虑自己得到的牌的先后顺序,自己手里能拿到的初始牌型组合一共有多少种呢?
*
* 请填写该整数,不要填写任何多余的内容或说明文字。
*
* @author Admin
*
*/
public class 牌型种数 {
static int count = 0;
public static void main(String[] args) {
// TODO Auto-generated method stub
dfs(0, 0);
System.out.println(count);
}
// 对每种类型的牌的数量进行枚举,统计最终符合条件的情况
private static void dfs(int depth, int sum) {
if (depth == 13) {
if (sum == 13)
count++;
return;
}
if (sum > 13)// 剪枝
return;
for (int i = 0; i <= 4; i++) {
dfs(depth + 1, sum + i);
}
}
}
模拟一下,答案为16。
package Contest_2015;
/**
*
* 加法变乘法
*
* 我们都知道:1+2+3+ ... + 49 = 1225 现在要求你把其中两个不相邻的加号变成乘号,使得结果为2015
*
* 比如: 1+2+3+...+10*11+12+...+27*28+29+...+49 = 2015 就是符合要求的答案。
*
* 请你寻找另外一个可能的答案,并把位置靠前的那个乘号左边的数字提交(对于示例,就是提交10)。
*
* 注意:需要你提交的是一个整数,不要填写任何多余的内容。
*
* 答案为16
*
* @author Admin
*
*/
public class 加法变乘法 {
public static void main(String[] args) {
int[] data = new int[50];
for (int i = 1; i < data.length; i++) {
data[i] = i;
}
// 暴力,枚举做乘法的位置
for (int i = 1; i < data.length - 1; i++) {
for (int j = i + 2; j < data.length - 1; j++) {
function(i, j, data);// 计算,并对符合条件的情况进行输出
}
}
}
// 计算data[1]+data[2]+...+data[index1]*data[index1+1]+...+data[index2]*data[index2+1]+...
private static void function(int index1, int index2, int[] data) {
int sum = data[index1] * data[index1 + 1] + data[index2] * data[index2 + 1];
int[] visit = new int[50];
visit[index1] = 1;
visit[index1 + 1] = 1;
visit[index2] = 1;
visit[index2 + 1] = 1;
for (int i = 1; i < data.length; i++) {
if (visit[i] == 0)
sum += data[i];
}
if (sum == 2015)
System.out.printf("%d*%d %d*%d\n", index1, index1 + 1, index2, index2 + 1);
}
}
白给题
package Contest_2015;
import java.util.Scanner;
/**
*
* 饮料换购
*
* 乐羊羊饮料厂正在举办一次促销优惠活动。乐羊羊C型饮料,凭3个瓶盖可以再换一瓶C型饮料,并且可以一直循环下去,但不允许赊账。
*
* 请你计算一下,如果小明不浪费瓶盖,尽量地参加活动,那么,对于他初始买入的n瓶饮料,最后他一共能得到多少瓶饮料。
*
* 输入:一个整数n,表示开始购买的饮料数量(0
public class 饮料换购 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int count = n;
while (n >= 3) {
n -= 3;
n++;
count++;
}
System.out.println(count);
}
}
package Contest_2015;
import java.util.Scanner;
public class 垒骰子 {
static long count = 0;
static boolean[][] martix;
private static int getOp(int n) {
if (n == 1)
return 4;
if (n == 4)
return 1;
if (n == 2)
return 5;
if (n == 5)
return 2;
if (n == 3)
return 6;
if (n == 6)
return 3;
return -1;
}
// 根据curHead确定nextBottom,并试探剩下的骰子
// nextHead
// nextBottom
// =======
// curHead
// curBottom
private static void dfs(int curHead, int height, int key) {
if (height == key) {
count++;
count %= 1000000000 + 7;
return;
}
// 选择nextBottom
for (int i = 1; i < 7; i++) {
// 排斥则跳过
if (martix[i][curHead]) {
continue;
}
int nextHead = getOp(i);
dfs(nextHead, height + 1, key);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
int n = sc.nextInt();// n个骰子
int m = sc.nextInt();
martix = new boolean[7][7];
for (int i = 0; i < m; i++) {
int x = sc.nextInt();
int y = sc.nextInt();
martix[x][y] = true;
martix[y][x] = true;
}
long begin = System.currentTimeMillis();
for (int i = 1; i < 7; i++) {
dfs(i, 1, n);// 初始1层
}
long end = System.currentTimeMillis();
// 骰子的四个面
long ans = count * (long) Math.pow(4, n) % (1000000000 + 7);
System.out.println(ans);
System.out.println(end - begin);
}
}
}
记忆化搜索至少可以过60%的数据
package Contest_2015;
import java.util.Scanner;
public class 垒骰子_记忆化搜索 {
static int n;
static long[][] record;
static boolean[][] martix;
public static void main(String[] args) {
// TODO Auto-generated method stub
init();
long ans = 0;
for (int i = 1; i < 7; i++) {
ans += dfs(i, 1);// 初始1层
}
// 骰子的四个面
ans = (ans % (1000000000 + 7)) * pow(4, n) % (1000000000 + 7);
System.out.println(ans);
}
private static long pow(int a, int b) {
long ans = 1;
for (int i = 0; i < b; i++) {
ans *= a;
ans %= (1000000000 + 7);
}
return ans;
}
private static int getOp(int n) {
if (n == 1)
return 4;
if (n == 4)
return 1;
if (n == 2)
return 5;
if (n == 5)
return 2;
if (n == 3)
return 6;
if (n == 6)
return 3;
return -1;
}
// 根据curHead确定nextBottom,并试探剩下的骰子
// nextHead
// nextBottom
// =======
// curHead
// curBottom
private static long dfs(int curHead, int height) {
if (record[curHead][height] != -1) {// 已计算过
return record[curHead][height];
}
if (height == n) {
record[curHead][height] = 1;
return record[curHead][height];
}
long temp = 0;
// 选择nextBottom
for (int i = 1; i < 7; i++) {
// 排斥则跳过
if (martix[i][curHead]) {
continue;
}
int nextHead = getOp(i);
temp += dfs(nextHead, height + 1);
}
record[curHead][height] = temp % (1000000000 + 7);
return record[curHead][height];
}
private static void init() {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();// n个骰子
int m = sc.nextInt();
martix = new boolean[7][7];
for (int i = 0; i < m; i++) {
int x = sc.nextInt();
int y = sc.nextInt();
martix[x][y] = true;
martix[y][x] = true;
}
record = new long[7][n + 1];
for (int i = 1; i < record.length; i++) {
for (int j = 1; j < record[i].length; j++) {
record[i][j] = -1;
}
}
}
}
package Contest_2015;
import java.util.Scanner;
public class 垒骰子_动态规划 {
static int n;
static long[][] dp;
static boolean[][] martix;
public static void main(String[] args) {
// TODO Auto-generated method stub
init();
for (int i = 2; i < dp.length; i++) {
for (int j = 1; j <= 6; j++) {
function(i, j);// 更新dp[i][j]
}
}
long sum = 0;
for (int i = 1; i <= 6; i++) {
sum += dp[n][i];
}
sum = (sum % (1000000000 + 7)) * pow(4, n) % (1000000000 + 7);
System.out.println(sum);
}
private static long pow(int a, int b) {
long ans = 1;
for (int i = 0; i < b; i++) {
ans *= a;
ans %= (1000000000 + 7);
}
return ans;
}
private static void function(int row, int col) {
for (int k = 1; k <= 6; k++) {
if (martix[col][getOp(k)] == true)// 排斥
continue;
dp[row][col] += dp[row - 1][k];
dp[row][col] %= (1000000000 + 7);
}
}
private static int getOp(int n) {
if (n == 1)
return 4;
if (n == 4)
return 1;
if (n == 2)
return 5;
if (n == 5)
return 2;
if (n == 3)
return 6;
if (n == 6)
return 3;
return -1;
}
private static void init() {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();// n个骰子
int m = sc.nextInt();
martix = new boolean[7][7];
for (int i = 0; i < m; i++) {
int x = sc.nextInt();
int y = sc.nextInt();
martix[x][y] = true;
martix[y][x] = true;
}
dp = new long[n + 1][7];
for (int i = 1; i <= 6; i++) {
dp[1][i] = 1;
}
}
}
面对100%的数据规模依旧超时
package Contest_2015;
import java.util.Scanner;
public class 垒筛子_动态规划_滚动数组 {
static int n;
static long[][] dp;
static boolean[][] martix;
public static void main(String[] args) {
// TODO Auto-generated method stub
init();
int T = n - 1;
int e = 0;
while (T-- != 0) {// 循环T次
e ^= 1;// 滚动(e.g. 10^00 = 10)
for (int j = 1; j <= 6; j++) {
function(e, j);// 更新dp[x][y]
}
}
long sum = 0;
for (int i = 1; i <= 6; i++) {
sum += dp[e][i];
}
sum %= (1000000000 + 7);
sum = (sum * quickPow(4, n)) % (1000000000 + 7);
System.out.println(sum);
}
// 快速幂,含取模。
private static long quickPow(int a, int b) {
if (b == 1)
return a;
long temp = quickPow(a, b / 2);
temp = temp * temp % (1000000000 + 7);
return (b % 2 == 0 ? 1 : a) * temp % (1000000000 + 7);
}
private static void function(int row, int col) {
long sum = 0;
for (int k = 1; k <= 6; k++) {
if (martix[col][getOp(k)] == true)// 排斥
continue;
sum += dp[row ^ 1][k];
sum %= (1000000000 + 7);
}
dp[row][col] = sum;
}
private static int getOp(int n) {
if (n == 1)
return 4;
if (n == 4)
return 1;
if (n == 2)
return 5;
if (n == 5)
return 2;
if (n == 3)
return 6;
if (n == 6)
return 3;
return -1;
}
private static void init() {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();// n个骰子
int m = sc.nextInt();
martix = new boolean[7][7];
for (int i = 0; i < m; i++) {
int x = sc.nextInt();
int y = sc.nextInt();
martix[x][y] = true;
martix[y][x] = true;
}
dp = new long[2][7];
for (int i = 1; i <= 6; i++) {
dp[0][i] = 1;
}
}
}
可以通过100%数据
package Contest_2015;
import java.util.Scanner;
public class 垒筛子_矩阵快速幂 {
static int n;
static long[][] martix;
static long[][] a;
static final int MOD = 1000000000 + 7;
static int op[] = { 0, 4, 5, 6, 1, 2, 3 };
public static void main(String[] args) {
// TODO Auto-generated method stub
init();
// 计算T^n-1
martix = quickMartix(martix, n - 1);
long sum = 0;
for (int i = 1; i <= 6; i++) {
for (int j = 1; j <= 6; j++) {
sum = (sum + martix[i][j]) % MOD;
}
}
sum %= MOD;
sum = (sum * quickPow(4, n)) % MOD;
System.out.println(sum);
}
// 6x6矩阵相乘
private static long[][] mulMartix(long[][] x, long[][] y) {
long[][] ans = new long[7][7];
for (int i = 1; i < x.length; i++) {// 遍历行
for (int j = 1; j < y[0].length; j++) {// 遍历列
for (int k = 1; k < y.length; k++) {// 遍历列中的每一个元素
ans[i][j] = (ans[i][j] + x[i][k] * y[k][j]) % MOD;
}
}
}
return ans;
}
// 矩阵快速幂
private static long[][] quickMartix(long[][] martix, int n) {
long[][] ans = new long[7][7];
for (int i = 1; i <= 6; i++)
ans[i][i] = 1;
while (n > 0) {
if (n % 2 != 0)
ans = mulMartix(ans, martix);
martix = mulMartix(martix, martix);
n /= 2;
}
return ans;
}
// 整数快速幂,含取模。
private static long quickPow(int a, int b) {
if (b == 1)
return a;
long temp = quickPow(a, b / 2);
temp = temp * temp % (1000000000 + 7);
return (b % 2 == 0 ? 1 : a) * temp % (1000000000 + 7);
}
private static void init() {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();// n个骰子
int m = sc.nextInt();
martix = new long[7][7];
for (int i = 1; i < martix.length; i++) {
for (int j = 1; j < martix[i].length; j++) {
martix[i][j] = 1;
}
}
for (int i = 0; i < m; i++) {
int x = sc.nextInt();
int y = sc.nextInt();
martix[x][op[y]] = 0;
martix[y][op[x]] = 0;
}
a = new long[7][2];
for (int i = 1; i <= 6; i++) {
a[i][1] = 1;
}
}
}
当成子集问题,暴力可以过一部分的数据。
package Contest_2015;
import java.util.Scanner;
public class 生命之树_暴力 {
static int n;
static int[] val;
static int[] mark;
static int[][] g;
static int max = -1;
public static void main(String[] args) {
// TODO Auto-generated method stub
init();
function(1);
System.out.println(max);
}
// 枚举所有节点选与不选的情况
private static void function(int index) {
if (index == n + 1) {
int sum = cal();
if (sum > max)
max = sum;
return;
}
// 不选
function(index + 1);
// 选
// 检查能否选,等价于已选择的节点中,是否与当前待选择的节点连通
if (isOk(index)) {
mark[index] = 1;
mark[0]++;
function(index + 1);
mark[index] = 0;
mark[0]--;
}
}
// 检查能否选,等价于已选择的节点中,是否与当前待选择的节点连通
private static boolean isOk(int index) {
if (mark[0] == 0)// 代表一个节点都没有
return true;
for (int i = 1; i < g[index].length; i++) {
if (g[index][i] == 1 && mark[i] == 1)
return true;
}
return false;
}
private static int cal() {
int sum = 0;
for (int i = 1; i < mark.length; i++) {
if (mark[i] == 1)
sum += val[i];
}
return sum;
}
private static void init() {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
val = new int[n + 1];
mark = new int[n + 1];
g = new int[n + 1][n + 1];
for (int i = 1; i < val.length; i++) {
val[i] = sc.nextInt();
}
for (int i = 0; i < n - 1; i++) {
int vertex1 = sc.nextInt();
int vertex2 = sc.nextInt();
g[vertex1][vertex2] = 1;
g[vertex2][vertex1] = 1;
}
}
}
只能过部分数据
package Contest_2015;
import java.util.Scanner;
/**
* 普通DFS搜索
*
* @author Admin
*
*/
public class 生命之树_搜索 {
static int n;
static int[] val;
static int[] mark;
static int[][] g;
public static void main(String[] args) {
// TODO Auto-generated method stub
init();
int max = val[1];
// O(n^2)时间复杂度,可以改为记忆化搜索
for (int i = 1; i <= n; i++) {
int temp = dfs(i);
if (temp > max)
max = temp;
}
System.out.println(max);
}
// 计算以root为根的子树权值之和的最大值(即不添加权值为负的子节点)
private static int dfs(int root) {
if (isEnd(root)) {// 所有邻接节点已访问
return val[root];
}
mark[root] = 1;// 标记已访问
int sum = val[root];
for (int i = 1; i <= n; i++) {// 访问邻接节点
if (g[root][i] == 1 && mark[i] == 0) {
int temp = dfs(i);
if (temp >= 0)// 只累加正权值的邻接节点
sum += temp;
}
}
return sum;
}
private static boolean isEnd(int root) {
for (int i = 1; i < n; i++) {
if (g[root][i] == 1 && mark[i] == 0)
return false;
}
return true;
}
private static void init() {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
val = new int[n + 1];
mark = new int[n + 1];
g = new int[n + 1][n + 1];
for (int i = 1; i <= n; i++) {
val[i] = sc.nextInt();
}
for (int i = 0; i < n - 1; i++) {
int vertex1 = sc.nextInt();
int vertex2 = sc.nextInt();
g[vertex1][vertex2] = 1;
g[vertex2][vertex1] = 1;
}
}
}
由普通搜索改进得来,邻接矩阵存图爆内存,所以选择邻接链表存图。
但由于Java消耗高,所以在OJ上还是过不了。
import java.util.ArrayList;
import java.util.Scanner;
/**
* 由普通DFS搜索-->记忆化搜索-->树形DP逐步改进
*
* @author Admin 5 0 -2 -3 -4 -5 4 2 3 1 1 2 2 5
*
*/
public class Main {
static int n;
static long max;
static int[] val;
static long[] dp;// mark[i]表示以i为根的最大权值和子树的权值和
static int[] mark;
static ArrayList<Integer>[] g;
public static void main(String[] args) {
init();
dfs(1);// 线性时间复杂度
System.out.println(max);
}
// 树形DP,自底向上
// 计算以root为根的子树权值之和的最大值(即不添加权值为负的子节点),并保存记录
private static void dfs(int root) {
if (isEnd(root)) {// 所有邻接节点已访问
mark[root] = 1;
dp[root] = val[root];
if (dp[root] > max)
max = dp[root];
return;
}
mark[root] = 1;// 标记已访问
long sum = val[root];
for (int index = 0; index < g[root].size(); index++) {// 访问邻接节点
int vertex = g[root].get(index);
if (mark[vertex] == 0) {
dfs(vertex);
if (dp[vertex] >= 0)// 只累加正权值的邻接节点
sum += dp[vertex];
}
}
dp[root] = sum;// 保存计算结果
if (dp[root] > max)
max = dp[root];
}
private static boolean isEnd(int root) {
if (g[root].size() == 0)
return true;
int lastVertex = g[root].get(g[root].size() - 1);
if (mark[lastVertex] == 0)
return false;
return true;
}
private static void init() {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
val = new int[n + 1];
dp = new long[n + 1];
mark = new int[n + 1];
g = new ArrayList[n + 1];
for (int i = 1; i < g.length; i++) {
g[i] = new ArrayList<Integer>();
}
for (int i = 1; i <= n; i++) {
val[i] = sc.nextInt();
}
for (int i = 0; i < n - 1; i++) {
int vertex1 = sc.nextInt();
int vertex2 = sc.nextInt();
g[vertex1].add(vertex2);
g[vertex2].add(vertex1);
}
max = val[1];
}
}
用C++重写了一遍上面的代码
#include
#include
#include
using namespace std;
int n;
long ans;
int val[100000 + 5];
int mark[100000 + 5];
long dp[100000 + 5];
vector<int> g[100000 + 5];
void dfs(int root) {
mark[root] = 1;
long sum = val[root];
for (int index = 0; index < g[root].size(); index++)
{
int vertex = g[root][index];
if (mark[vertex] == 0) {
dfs(vertex);
if (dp[vertex] >= 0)
sum += dp[vertex];
}
}
dp[root] = sum;
if (dp[root] > ans)
ans = dp[root];
}
int main() {
memset(mark, 0, sizeof(mark));
memset(dp, 0, sizeof(dp));
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> val[i];
}
for (int i = 0; i < n-1; i++)
{
int vertex1, vertex2;
cin >> vertex1 >> vertex2;
g[vertex1].push_back(vertex2);
g[vertex2].push_back(vertex1);
}
ans = val[1];
dfs(1);
cout << ans << endl;
return 0;
}