先说一下全排列:
对于R={r1,r2,…,rn},进行n个元素的全排列,设Ri=R – {ri}。结合X元素的全排列记为Perm(X),(ri)Perm(X)表示在全排列Perm(X)的每个排列前面加上前缀ri的得到的序列。R的全排列可归纳定义如下:
n=1时,Perm(R)=(r),其中r是R中的唯一元素;
n>1时,Perm(R)由(r1)Perm(R1), (r2)Perm(R2),…, (rn)Perm(Rn)构成。
显然,部分排列,只要控制递归结束条件即可。
再说组合:
组合与排列相比,忽略了元素的次序,因此我们只需将元素按编号升序排列(或则其他的规则)即可。
代码如下:
public class Main {
static int count;
public static void main(String[] args) {
int a[] = {1, 2, 3, 4};
count = 0;
permutation(a, 0, 4);
System.out.println("count=" + count);
count = 0;
combination(a, 0, 3, 0);
System.out.println("count=" + count);
}
static void combination(int a[], int nowp, int m, int left){//zuhe
/**//*
* 求a[]中m个元素的组合
* nowp表示当前已经组合好的元素的个数
* left,只能选择编号为left和它之后的元素 进行交换
*/
if(nowp == m){
count++;
for(int i = 0; i < m; i++){
System.out.print(a[i] + " ");
}
System.out.println();
}
else{
for(int i = left; i < a.length; i++){
swap(a, nowp, i);
combination(a, nowp + 1, m, i + 1);
swap(a, nowp, i);
}
}
}
static void permutation(int a[], int nowp, int m){// pailie
/**//*
* 求a[]m个元素的排列
* nowp,当前已经排列好的元素的个数
*/
if(nowp == m){
count++;
for(int i = 0; i < m; i++){
System.out.print(a[i] + " ");
}
System.out.println();
}
else{
for(int i = nowp; i < a.length; i++){
swap(a, i, nowp);
permutation(a, nowp + 1, m);
swap(a, i, nowp);
}
}
}
static void swap(int a[], int n, int m){
int t = a[n];
a[n] = a[m];
a[m] = t;
}
}
posted @
2013-07-06 10:54 小鼠标 阅读(1320) |
评论 (0) |
编辑 收藏
题意:
给定两个非负数,可以用较小那个数的任意正整数倍数去减较大那个数,但要保证结果非负。两个人轮流操作,结果中先出现0的那个人获胜。
第一次做博弈题,不知如何下手。这里认真分析一下。
假设两个数a b,他们的大小关系无非是a>b,a<b,a==b中的一种,对本题二样前两种其实是同一种情况,第三种情况时结果已经出来了(此时轮到谁谁获胜)。
我们再来讨论a>b(a<b)的情况,又可细分为:
b<a<2 * b (1)
a == 2 * b (2)
a >2*b (3)
对情况(1),选手没得选,只能用较小的树去减较大的数,下一个状态一定是b,a%b。也就是说这种状态的出现不会影响最终结果。
情况(2),显然,也可以结束游戏了,当前选手赢了。
情况(3),此时选手可以决定下一个状态是下面状态中的一种:
a-b, b
a-2*b, b
a-3*b, b
.
.
.
a%b+b, b (k-1)
b, a%b (k)
由于两个选手必须轮流操作,因此,两相邻的状态的输赢结果一定相反。而此时,选手恰恰可以决定是到状态(k-1)还是到状态(k)(状态(k-1)的下一个状态一定是状态(k),因为情况(1)),也就是说此时选手能决定自己的输赢。
综上我们可以得到如下结论
出现下述情况之一的就可断定当前选手获胜:
1.a==b
2.a>=2*b
细节:如果一开始输入数据为a,0,本题认为Ollie wins
import java.io.*;
import java.util.*;
class Main {
static boolean firstWin;
public static void main(String[] args) throws IOException{
int a, b;
Scanner sc = new Scanner(System.in);
a = sc.nextInt();
b = sc.nextInt();
while(a != 0 || b != 0){
firstWin = true;//初始认为Stan wins
if(a >= b)
get(a, b);
else
get(b, a);
if(firstWin)
System.out.println("Stan wins");
else
System.out.println("Ollie wins");
a = sc.nextInt();
b = sc.nextInt();
}
}
public static void get(int a, int b){//a >= b
if(a == b)
return;
if(b == 0){//边界情况,如果一开始输入是b为零,我们认为Ollie wins
firstWin = !firstWin;
return;
}
if(a / b >= 2)
return;
firstWin = !firstWin;
get(b, a % b);
}
}
posted @
2013-05-04 16:21 小鼠标 阅读(258) |
评论 (0) |
编辑 收藏
Counting fractions
TimeLimit: 2000MS MemoryLimit: 65536 Kb
Totalsubmit: 39 Accepted: 6
Description
Consider the fraction, n/d, where n and d are positive integers. If n <= d and HCF(n,d)=1, it is called a reduced proper fraction.
If we list the set of reduced proper fractions for d <= 8 in ascending order of size, we get:
1/8, 1/7, 1/6, 1/5, 1/4, 2/7, 1/3, 3/8, 2/5, 3/7, 1/2, 4/7, 3/5, 5/8, 2/3, 5/7, 3/4, 4/5, 5/6, 6/7, 7/8
It can be seen that there are 21 elements in this set.
How many elements would be contained in the set of reduced proper fractions for d <= x?
Input
The input will consist of a series of x, 1 < x < 1000001.
Output
For each input integer x, you should output the number of elements contained in the set of reduced proper fractions for d <= x in one line.
Sample Input
3
8
Sample Output
3
21
Hint
HCF代表最大公约数
这里主要说一下素数筛法,该方法可以快速的选取出1~N数字中的所有素数。时间复杂度远小于O(N*sqrt(N))
方法为:从2开始,往后所有素数的倍数都不是素数。最后剩下的数都是素数。
再说说欧拉公式,用来解决所有小于n中的数字有多少个与n互质,用Ψ(n)表示。
Ψ(n)=n*(1-1/q1)*(1-1/q2)*……*(1-1/qk),n为和数,其中qi为n的质因数。
Ψ(n)=n-1,n为质数
注意:关于数论的题很容易超过int类型的范围,多考虑用long long类型。
欧拉函数请参阅:
http://zh.wikipedia.org/zh-cn/%E6%AC%A7%E6%8B%89%E5%87%BD%E6%95%B0
代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define LEN 1100010
using namespace std;
int len0 = (int)sqrt(LEN);
int isp[LEN];//isprime?
int pr[LEN];//依次记录素数
int pct;// prime count
long long rs[LEN];//fi(n)
int main()
{
int i, j;
int x;
memset(isp, -1, sizeof(isp));
for(int i = 2; i <= len0; i++)//素数筛法选出素数
{
if(isp[i])
{
for(int j = i * 2; j < LEN; j += i)
isp[j] = 0;
}
}
pct = 0;
for(int i = 2; i < LEN; i++)//记下选出的素数
if(isp[i])
pr[pct++] = i;
for(int i = 0; i < LEN; i++)
rs[i] = i;
for(int i = 0; i < pct; i++)
{
rs[pr[i]]--;
for(int j = pr[i] * 2; j < LEN; j += pr[i])
{
rs[j] = rs[j] / pr[i] * (pr[i] - 1);//rs[]要定义成long long类型,因为计算过程中乘法会超过int类型的取值范围
//rs[j] -= rs[j] / pr[i];
}
}
while(scanf("%d", &x) != EOF)
{
long long sum = 0;
for(int i = 2; i <= x; i++)
sum += rs[i];
//printf("%lld\n", sum);
cout << sum << endl;//用cout输出,不用考虑使用%lld还是%I64d
}
//system("pause");
return 0;
}
posted @
2013-04-30 21:26 小鼠标 阅读(1287) |
评论 (0) |
编辑 收藏
摘要: 最大值
TimeLimit: 1000MS MemoryLimit: 65536 Kb
Totalsubmit: 161 Accepted: 4
Description
Little Ming很喜欢训练自己的快速读能力,他最近找到一种新的考验并训练快速读能力的方法,在一行具...
阅读全文
posted @
2013-04-28 18:47 小鼠标 阅读(246) |
评论 (0) |
编辑 收藏
括号的两种不同表示间的转换。
解题思路比较偷懒:先将括号恢复成我们喜欢看的形式,然后再转换成w型的表示方式。
代码
1import java.io.*;
2import java.util.*;
3class Main
4{
5 public static void main(String[] args)
6 {
7 Scanner sc = new Scanner(System.in);
8 int t = sc.nextInt();
9 for(int i = 0; i < t; i++)
10 {
11 int n = sc.nextInt();
12 int a = 0;
13 int b = 0;
14 StringBuffer strBuf = new StringBuffer();
15 for(int j = 0; j < n; j++)
16 {
17 b = sc.nextInt();
18 for(int k = 0; k < b - a; k++)
19 {
20 strBuf.append('(');
21 }
22 strBuf.append(')');
23 a = b;
24 }
25 boolean first = true;
26 for(int j = 0; j < strBuf.length(); j++)
27 {
28 if(strBuf.charAt(j) == ')')
29 {
30 int bi = getW(strBuf, j);
31 if(first)
32 {
33 System.out.print(bi);
34 first = false;
35 }
36 else
37 {
38 System.out.print(" " + bi);
39 }
40 }
41 }
42 System.out.println();
43 }
44 }
45 private static int getW(StringBuffer buf, int p)
46 {
47 int count = 0;
48 int right = 1;
49 for(int i = p - 1; i >= 0; i--)
50 {
51 if(buf.charAt(i) == ')')
52 {
53 right++;
54 }
55 else if(buf.charAt(i) == '(')
56 {
57 count++;
58 if(right == 1)
59 return count;
60 right--;
61 }
62 }
63 return -1;
64 }
65}
66
posted @
2013-04-18 22:44 小鼠标 阅读(153) |
评论 (0) |
编辑 收藏
题意:
求给定矩阵的最大子矩阵和。
先来回顾一下
一维的最大子段和问题:给定一个序列a[n],求a[n]的最大子段和。
DP的递推公式为b[j] = max{b[j - 1] + a[j], a[j]}. 其中b[j]表示a[n]中包含b[j]的最大子段和。时间复杂度为O(n)
对于二维矩阵而言,我们可以通过把多行压缩(按列求和)成一行的方式将问题
转换为一维。
行压缩时枚举复杂度为O(N^2)。因此整个求解过程的时间复杂度为O(N^3)。
代码
1import java.io.*;
2import java.util.*;
3class Main
4{
5
6 public static void main(String[] args)
7 {
8
9 Scanner sc = new Scanner(System.in);
10 int N;
11 N = sc.nextInt();
12 int nums[][] = new int[N][N];
13
14 for(int i = 0; i < N; i++)
15 {
16 for(int j = 0; j < N; j++)
17 {
18 nums[i][j] = sc.nextInt();
19 }
20 }
21 int ns[] = new int[N];
22 int max = 0;
23 for(int i = 0; i < N; i++)//begin row
24 {
25 for(int j = i; j < N; j++)// end row
26 {
27 Arrays.fill(ns, 0);
28 for(int k = 0; k < N; k++)// get ns[]
29 {
30 for(int ii = i; ii <= j; ii++)
31 {
32 ns[k] += nums[ii][k];
33 }
34 }
35 int t = thisMaxSum(ns);
36 if(t > max)
37 max = t;
38 }
39 }
40 System.out.println(max);
41 }
42 private static int thisMaxSum(int[] ns)
43 {
44 int max = 0;
45 int b = 0;
46 for(int i = 0; i < ns.length; i++)
47 {
48 if(b + ns[i] > ns[i])
49 b += ns[i];
50 else
51 b = ns[i];
52 if(b > max)
53 max = b;
54 }
55 return max;
56 }
57
58}
59
posted @
2013-04-17 15:32 小鼠标 阅读(281) |
评论 (0) |
编辑 收藏
题意:找出矩阵中的最长下降序列的长度。
解题思路:
1.回溯,时间复杂度,指数级别。这是一种很容易想到的做法,不过会超时。
2.动态规划,时间复杂度O(N^2)。相信我们都学过一维的
最长上升子序列问题,这一题是一维的变形,我们只需稍加转换就可以转换为一维的。
先来回想一下一维的最长上升子序列的做法:对一个给定的节点p,我们只需枚举p前面的所有节点的最长上升子序列的长度,用p前面的节点的长度去试图更新p的长度即可。
我们如何将本题转化为一维的问题呢?我们只需将矩阵中的所有点按照他的high排序,然后按照一维的处理即可。只不过p前面的节点在更新p时还要考虑他们在矩阵中的相对位置,因为只有跟p相邻的四个点才有可能去更新p点的长度。
代码
1import java.io.*;
2import java.util.*;
3class Main
4{
5 private static int R, C;
6 private static MyNode[] nds = new MyNode[110 * 110];
7 public static void main(String[] args)
8 {
9
10 Scanner sc = new Scanner(System.in);
11 R = sc.nextInt();
12 C = sc.nextInt();
13 int count = 0;
14 for(int i = 0; i < R; i++)
15 {
16 for(int j = 0; j < C; j++)
17 {
18 int h = sc.nextInt();
19 nds[count++] = new MyNode(i, j, h);
20 }
21 }
22 Arrays.sort(nds, 0, count);
23 ///
24 //for(int i = 0; i < count; i++)
25 // System.out.println("::" + nds[i].getH());
26 //
27 int lens[][] = new int[R][C];
28 for(int i = 0; i < R; i++)
29 Arrays.fill(lens[i], 1);
30 for(int i = 1; i < count; i++)
31 {
32 for(int j = 0; j < i; j++)
33 {
34 int r2 = nds[i].getR();
35 int c2 = nds[i].getC();
36 int h2 = nds[i].getH();
37
38 int r1 = nds[j].getR();
39 int c1 = nds[j].getC();
40 int h1 = nds[j].getH();
41 if(Math.abs(r2 - r1) + Math.abs(c1 - c2) == 1 && h2 > h1
42 && lens[r2][c2] <= lens[r1][c1])
43 {
44 lens[r2][c2] = lens[r1][c1] + 1;
45 }
46 }
47 }
48 int max = 0;
49 for(int i = 0; i < R; i++)
50 {
51 for(int j = 0; j < C; j++)
52 if(lens[i][j] > max)
53 max = lens[i][j];
54 }
55 System.out.println(max);
56 }
57
58}
59class MyNode implements Comparable<MyNode>
60{
61 private int r;
62 private int c;
63 private int h;
64 public MyNode(int r, int c, int h)
65 {
66 this.r = r;
67 this.c = c;
68 this.h = h;
69 }
70 public int getR()
71 {
72 return r;
73 }
74 public int getC()
75 {
76 return c;
77 }
78 public int getH()
79 {
80 return h;
81 }
82 public int compareTo(MyNode n2)
83 {
84 return h - n2.h;
85 }
86}
posted @
2013-04-16 18:36 小鼠标 阅读(397) |
评论 (0) |
编辑 收藏
摘要: 题意:按照指定格式输出目录树。要求同一层下的file要按文件名排序。解题步骤:1.用deep记录当前目录深度,遇到dir,deep++,遇到] deep--2.用strlist记录所有未输出的file,用栈stack记录当前目录下的file表的开始下标。遇到]或者*则输出当前目录下的所有file,并从strlist中删除,相应的下标出栈(stack).
代码Code highlighting p...
阅读全文
posted @
2013-04-14 22:30 小鼠标 阅读(304) |
评论 (0) |
编辑 收藏
摘要: 题意:对比连个图是否相同。相同的条件是A图中每个连通的区域都在B图中有一块相同的区域与之对应。经过旋转后对应也可以。解题思路:思路一:暴力式。遍历并存储A图中所有联通的区域,然后在B中逐个寻找与之对应的图形。思路二:等价转化式。比较两个图中对应点的“连通度”是否相同。相同输出YES。空白点的连通度为0,空白点的连通度为它所在行和列与之相连的非空白点的个数。方式二非常巧妙,将...
阅读全文
posted @
2013-04-14 20:10 小鼠标 阅读(499) |
评论 (0) |
编辑 收藏
摘要: 题意:字处理程序检查输入的单词是否正确。若不正确,则按照规则在字典中找与该单词相近的单词。解题思路:按照题目给出的规则模拟。要点:要注意查找效率,遍历会超时。此处用的是TreeMap,查找效率log2(N)。
代码Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.c...
阅读全文
posted @
2013-04-09 15:17 小鼠标 阅读(133) |
评论 (0) |
编辑 收藏