分治:
分解成子問題,分別解決子問題,合併子問題的解。
且子問題是相互獨立的。可以用遞歸或非遞歸實現。
- 減治(子問題個數爲一) :n地階乘
- 分支(子問題個數大於一):Fibonacci數列地求解
關鍵:
1.找到遞歸式。F(n)= do(F(n-1));
2.找到遞歸邊界:if(n==1) return 1.
全排列,n皇后
貪心
關鍵:似乎可行的策略。
簡單貪心:(獲得最大收益,肯定從單價最高的先賣。)
區間貪心:先選擇左端點大的,左端點一樣大選擇右端點小的。
求最優解: 動態規劃、貪心算法。
看每次的選擇:
整體最優解可以拆成局部最優解(貪心)。
單元最短路徑(Dijkstra、Floyd)、最小生成樹(Prim、Kruskal)、哈夫曼編碼(哈夫曼樹,找兩個最小的結點變成新結點)
揹包問題:拆成每次最優解解決:動態規劃
如果考慮特例,舉出反例:用貪心算法得出的解不是最優解那就用動態規劃。
二分
基於有序序列
的查找算法
1.嚴格遞增序列
int BinarySearch(int a[], int low, int high, int x)
{
int mid;
while (low <= high)//要有等於號,可能恰好就在中間,不等於的話就搜不到了。
{
mid = (low + high) / 2;
if (**x == a[mid]**) return mid;
if (x < a[mid]) {
high = mid - 1;
}else {
low = mid + 1;
}
}
return -1;
}
x == a[mid]: 條件是等於x的元素位置
2.非嚴格遞增
返回第一個大於等於x的位置(可能有重複x) || 返回第一個大於x的位置
int BinarySoloSearch(int a[], int low, int high, int x)
{
//返回第一個大於等於x的地方(可能有重複x)
//尋找第一個滿足某條件的元素位置
//因爲mid 就是我要尋找的位置
int mid;
while (low < high) { //退出條件 low == high 唯一位置
mid = (low + high) / 2;
if ( **a[mid] >=x** ) { //尋找第一個>=x 的數 :現在中間的數比x要大
high = mid; // 我要去左區間找
}
else {
low = mid + 1;
}
}
return low;
}
a[mid] >=x的不同:滿足某一條件的元素位置:往哪個區間找。
3.二分法拓展:精度問題
#include<iostream>
#include<cmath>
using namespace std;
const double esp = 1e-5; //(10^5)
double eal() {
double left = 1, right = 2, mid;
while (right - left > esp) {//退出條件:精度小於10^-5
mid = (left + right) / 2;
if (pow(mid, 2) > 2) {//平方比二大 比 判斷 該數比根號2大精確
right = mid;
}
else {
left = mid;
}
}
return mid;
}
int main()
{
cout << eal();
}
1.41421
可以轉換爲求方程的解
木棒切割: 有兩端,切割的長度越長,木棒椴數越少。
木棒切割
切割成K段:求長度相等的木棒 : 最長能有多長
int cut(int a[], int size, int length)
{
int sum = 0;
for (int i = 0; i <size; i++)
{
sum += a[i] / length;
}
return sum;
}
int main()
{
int sticks[100],n,K;
cin >> n>>K;
for (int i = 0; i < n; i++)
{
cin >> sticks[i];
}
sort(sticks, sticks + n);
int k,low = 0, high = sticks[n-1],mid;
// 最大取最大的那根木棒
while (low <= high) { // 當low>high的時候跳出
mid = (high+low)/2;
k = cut(sticks, n,mid);
if (k < K && cut(sticks, n, mid - 1) == K) break;//找到第一個切出來的數目比需要切出來的數目小的(找長度最大的)跳出
if (k < K && cut(sticks, n, mid - 1) != K) high = mid;
else low=mid+1;
}
if (low > high)cout << mid;
else cout << mid-1; //長度變小一點就滿足”最長“
}
c++中使用scanf
添加
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
memset: 對數組中每一個元素賦相同的值(0/-1)
int a[5] = { 2,3,5,4,6 };
memset(a, -1, sizeof(a));
指針
指針是個unsigned類型的整數
指針變量 數據類型*
p 用於存放指針(即地址),而&爲取地址符。所以都是 int* p = &a
int* p = &a;
等價
int* p;
p=&a;
數組與指針
數組名稱也作爲數組的首地址使用。a==&a[0],a+i==&a[i]
結構體初始化
typedef struct Stu{
int x;
int y;
int sum;
Stu() {}
Stu(int _x, int _y, int _sum):x(_x), y(_y), sum(_sum) {}
}Stu;
浮點數比較(精確)
const double eps = 1e-8;
const double Pi = acos(-1.0);
#define Equ(a,b) ((fabs((a)-(b)))<(eps))
#define More(a,b) ((a)-(b)<(eps))
#define Less(a,b) ((a)-(b)<(-eps))
學生名次排序
相同的成績同一名次,但是排序不疊加。
分批排序:一批中有K個人。總人數爲 t。
sort(先排好序)
stu[t - K].local_rank = 1;
for (int j = t-K+1; j < t; j++)
{
if (stu[j].score == stu[j - 1].score) stu[j].local_rank = stu[j - 1].local_rank;
else {//從第二名來
stu[j].local_rank = j-(t - K) + 1;
}
}
排總名次
sort(先排好序)
stu[0].rank = 1;
for (int i = 1; i < t; i++)
{
if(stu[i].score==stu[i-1].score)stu[i].rank = stu[i-1].rank;
else {
stu[i].rank = i + 1;
}
}
哈希散列
將元素通過一個函數轉換爲整數,並且該整數可以儘量唯一地代表這個元素。
H(key)=key%mod
處理衝突地辦法初試已經學過。
字符串hash:用ASCII碼解決,將字符串轉換爲整數。
#include<iostream>
using namespace std;
// 最大整數:26*26*26-1 只看前三個字母
int hashTable[26 * 26 * 26 + 10] = { 0 };
int hashFunc(char S[], int len) {
int id = 0;
for (int i = 0; i < len; i++)
{
id = id * 26 + (S[i] - 'A');
}
return id;
}
int main()
{
int n, m;
cin >> n >> m;
//可以存100個存在查詢地字符串
char S[100][5],temp[5];
for (int i = 0; i < n; i++)//n個字符串
{
cin >> S[i];
int id = hashFunc(S[i], 3);
hashTable[id]++;
}
for (int i = 0; i < m; i++)//m個查詢字符串
{
cin >> temp;
int id = hashFunc(temp, 3);
cout << hashTable[id];
//輸出有多少個temp
}
}