1.組合問題:
問題描述:對於一組各不相同的數字,從中任意抽取1-n個數字,構成乙個新的集合。求出所有的可能的集合。例如,對於集合,其所有子集為,,,,,, 給定乙個陣列(元素各不相同),求出陣列的元素的所有非空組合(即陣列的所有非空子集)
解法一:位向量法。用乙個輔助陣列表示各個元素的狀態。1表示在集合中,0表示不在陣列中。遞迴地求解所有的子集。
演算法描述如下://這裡的演算法對空集也輸出了,可修改之使得只輸出非空集合。
[cpp]view plain
copy
print?
void
getsubset(
int*a,
int*b,
intn,
intk)else
if(i==(n-1))\n"
);
} if
(b[i])
} return
; }
b[k] = 1;
getsubset(a,b,n,k+1);
b[k] = 0;
getsubset(a,b,n,k+1);
}
解法二:點陣圖的思想。思路類似與解法一位向量。用n個位來儲存相應的元素是否在集合中,如果在集合中,相應位為1.否則為0;
**示例://注:這裡用的是位陣列而不是c++中的bitmap
[cpp]view plain
copy
print?
void
print_subset(
intn,
ints)
printf("}\n"
);
} void
subset(
intn)
}
只需要呼叫subset(n)即可輸出1->n個數字的所有組合。或者修改輸出部分為輸出乙個特定集合的組合。
2.。排列問題。
給定一組不相同的數字。求出這n個數字的各種排列形式。稱為排列問題。
解法一:暴力搜尋,對於乙個全排列問題,相當於搜尋乙個具有n個n-1叉數的深林。暴力搜尋之,得到所有的全排列形式。**如下:
[cpp]view plain
copy
print?
#include
#include
void
output(
int*a,
intn)
printf("\n"
);
} void
perm(
int*a,
int*b,
intn,
intk)else
} if(flag)
} }
} int
main()
perm(a,b,3,0);
}
解法二:模擬回溯法生成排列的過程,對於已知的乙個序列,如果交換其中兩個元素的,會得到新的序列。思路類似於生成組合問題。演算法描述如下:
[cpp]view plain
copy
print?
void
permutation(
int*a,
intn,
intk)
printf("}\n"
);
return
; }
for(
inti = k;i
swap(&a[i],&a[k]);
permutation(a,n,k+1);
swap(&a[i],&a[k]);
} }
解法三:c++ 中stl中next_permutation()方法。注意這種方法要得到所有的排列,需要原始陣列為遞增有序的,可先對其qsort()
[cpp]view plain
copy
print?
doprintf("}\n"
);
}while
(next_permutation(a,a+n));
//todo全排列中有重複元素的演算法總結
3.笛卡爾積問題。
@xuzuning
問題描述:笛卡爾(descartes)乘積又叫直積。設a、b是任意兩個集合,在集合a中任意取乙個元素x,在集合b中任意取乙個元素y,組成乙個有序對(x,y),
把這樣的有序對作為新的元素,他們的全體組成的集合稱為集合a和集合b的直積,記為a×b,即a×b=。n對集合的笛卡爾積由此遞迴定義得到。
[php]view plain
copy
print?
<?php
/** 笛卡爾(descartes)乘積又叫直積。設a、b是任意兩個集合,在集合a中任意取乙個元素x,在集合b中任意取乙個元素y,組成乙個有序對(x,y),
* 把這樣的有序對作為新的元素,他們的全體組成的集合稱為集合a和集合b的直積,記為a×b,即a×b=。
* @author xuzuning
*/function
descartes()
$a=
array_shift($t
);
if(!
is_array($a
))
$a=
array_chunk($a
, 1);
//目的是分解成array(a)這樣的形式,便於後面的合併
dowhile($t
);
return
$r;
} $arr
= array
( array
('a1'
,'a2'
,),
'b',
array
('c1'
,'c2'
,),
array
('d1'
,'d2'
,'d3'
) );
$r= descartes(
$arr
);
?>
上述求全排列和子集的方法,稱為回溯法。對於回溯法,有乙個基本的框架(模式):
[plain]view plain
copy
print?
void backtrack(int n,int k)
else
}
利用這個模式可以寫出例如組合,全排列,子集,八皇后等問題。
八皇后問題的解法:比較經典,不需過多解釋。
排列 組合 子集
目錄 result def backtrack 路徑,選擇列表 if 滿足結束條件 result.add 路徑 return for 選擇 in 選擇列表 做選擇backtrack 路徑,選擇列表 撤銷選擇 排列問題,講究順序 即 2,2,3 與 2,3,2 視為不同列表時 需要記錄哪些數字已經使用...
演算法總結 排列組合
46 全排列 關鍵點 使用used記錄已使用的用數字 class solution def permute self,nums list int list list int self.res self.used false len nums self.generatearrange nums,0,r...
排列組合問題總結
根本思想還是組合數學的加法原則,將乙個狀態分成幾個不相交的狀態,然後用加法原則加起來即可 如果 n m c n 1,m 1 c n 1,m 1 c n 1,m 1 否則 n000 分析 使用插板法 n個球中間有n 1個間隙,現在要分成m個盒子,而且不能有空箱子,所以只要在n 1個間隙選出m 1個間隙...