先說一下全排列:
對于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 小鼠標 閱讀(1326) |
評論 (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 小鼠標 閱讀(262) |
評論 (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 小鼠標 閱讀(1292) |
評論 (0) |
編輯 收藏
摘要: 最大值
TimeLimit: 1000MS MemoryLimit: 65536 Kb
Totalsubmit: 161 Accepted: 4
Description
Little Ming很喜歡訓練自己的快速讀能力,他最近找到一種新的考驗并訓練快速讀能力的方法,在一行具...
閱讀全文
posted @
2013-04-28 18:47 小鼠標 閱讀(254) |
評論 (0) |
編輯 收藏
括號的兩種不同表示間的轉換。
解題思路比較偷懶:先將括號恢復成我們喜歡看的形式,然后再轉換成w型的表示方式。

代碼
1
import java.io.*;
2
import java.util.*;
3
class 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 小鼠標 閱讀(161) |
評論 (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)。

代碼
1
import java.io.*;
2
import java.util.*;
3
class 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 小鼠標 閱讀(293) |
評論 (0) |
編輯 收藏
題意:找出矩陣中的最長下降序列的長度。
解題思路:
1.回溯,時間復雜度,指數級別。這是一種很容易想到的做法,不過會超時。
2.動態規劃,時間復雜度O(N^2)。相信我們都學過一維的
最長上升子序列問題,這一題是一維的變形,我們只需稍加轉換就可以轉換為一維的。
先來回想一下一維的最長上升子序列的做法:對一個給定的節點p,我們只需枚舉p前面的所有節點的最長上升子序列的長度,用p前面的節點的長度去試圖更新p的長度即可。
我們如何將本題轉化為一維的問題呢?我們只需將矩陣中的所有點按照他的high排序,然后按照一維的處理即可。只不過p前面的節點在更新p時還要考慮他們在矩陣中的相對位置,因為只有跟p相鄰的四個點才有可能去更新p點的長度。

代碼
1
import java.io.*;
2
import java.util.*;
3
class 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
}
59
class 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 小鼠標 閱讀(403) |
評論 (0) |
編輯 收藏
摘要: 題意:按照指定格式輸出目錄樹。要求同一層下的file要按文件名排序。解題步驟:1.用deep記錄當前目錄深度,遇到dir,deep++,遇到] deep--2.用strlist記錄所有未輸出的file,用棧stack記錄當前目錄下的file表的開始下標。遇到]或者*則輸出當前目錄下的所有file,并從strlist中刪除,相應的下標出棧(stack).
代碼Code highlighting p...
閱讀全文
posted @
2013-04-14 22:30 小鼠標 閱讀(311) |
評論 (0) |
編輯 收藏
摘要: 題意:對比連個圖是否相同。相同的條件是A圖中每個連通的區域都在B圖中有一塊相同的區域與之對應。經過旋轉后對應也可以。解題思路:思路一:暴力式。遍歷并存儲A圖中所有聯通的區域,然后在B中逐個尋找與之對應的圖形。思路二:等價轉化式。比較兩個圖中對應點的“連通度”是否相同。相同輸出YES。空白點的連通度為0,空白點的連通度為它所在行和列與之相連的非空白點的個數。方式二非常巧妙,將...
閱讀全文
posted @
2013-04-14 20:10 小鼠標 閱讀(505) |
評論 (0) |
編輯 收藏
摘要: 題意:字處理程序檢查輸入的單詞是否正確。若不正確,則按照規則在字典中找與該單詞相近的單詞。解題思路:按照題目給出的規則模擬。要點:要注意查找效率,遍歷會超時。此處用的是TreeMap,查找效率log2(N)。
代碼Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.c...
閱讀全文
posted @
2013-04-09 15:17 小鼠標 閱讀(141) |
評論 (0) |
編輯 收藏