分治法與動態規劃


1、二分查找
已知有序的序列,比如:2,3,3,5,9,9,9,12,12,13,15,22,22,22,22,25,25,23,91,95
有整數x,比如: x=23
要求找到一個剛好比x稍微大一點的元素位置


當數組較大的時候,需要二分查找加快速度。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int f(int * a, int b, int e, int x){
	if (e - b == 1){
		if (a[b] > x){
			return b;
		}
		else{
			return e;
		}
	}
	int m = (b + e) / 2;
	if(x >= a[m]){
		return f(a, m , e, x);
	}
	else{
		return f(a, b, m, x);	
	}
}
int f1(int * a, int len, int x){
	if(x > a[len - 1]){
		return -1;
	}
	return f(a, 0, len, x);
}
int main(){
	int a[] = {2,3,3,5,9,9,9,12,12,13,15,22,22,22,22,25,25,23,91,95};
	printf("%d", f1(a, 20, 32));
}
2、最大序列和

數組中整數有正有負
求一連續子段,使得和最大化
例如:
2,4,-7,5,2,-1,2,-4,3
最大連續段:
5,2,-1,2

其最大和爲8

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int f(int * a, int b, int e, int * k1, int * k2){
	if(e - b == 1){
		if(a[b] > 0){
			return a[b];
		}
		return 0;
	}
	int c = (b + e) / 2;
	int m1 = 0, m2 = 0, n1 = 0, n2 = 0;
	int d1 = f(a, b, c, &m1, &m2);
	int d2 = f(a, c, e, &n1, &n2);
	int e1 = 0;
	int e2 = 0;
	int g = 0;
//	*k1 = c;
//	*k2 = c;
	for (int i = c; i >= b; i--){
		 g += a[i];
		 if (g > e1){
		 	e1 = g;
		 	*k1 = i;
		 }
	}
	g = 0;
	for(int i = c + 1; i < e; i++){
		g += a[i];
		if(g > e2){
			e2 = g;
			*k2 = i;
		}
	}
	printf("k1 :%d  k2 : %d\n", *k1, *k2);
	int h = 0;
		if(h < e1 + e2){
		h = e1 + e2;
	}
	if(h < d1){
		h = d1;
		*k1 = m1;
		*k2 = m2;
	}
	if(h < d2){
		h = d2;
		*k1 = n1;
		*k2 = n2;
	}
	return h;
}
int main(){
	int a[] = {2,4,-7,5,2,-1,2,-4,3};
	int b = 0, c = 0;
	printf("%d\n", f(a, 0, 9, &b, &c));
	printf("%d %d\n", b, c);
	for(int i = b; i <= c; i++){
		printf("%d ", a[i]);
	}
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int f(int * a, int b, int * d1, int * d2){
	int d = 0;
	for(int i = 0; i < b; i++){
		for(int j = i; j < b; j++){
			int c = 0;
			for(int k = i; k <= j; k++){
				c += a[k];
			}
			if(c > d){
				d = c;
				*d1 = i;
				*d2 = j;
			}
			printf("i: %d  j:%d %d\n", i, j, c);
		}
	}
	return d;
}
int f2(int * a, int b, int * d1, int * d2){
	int c = 0;
	int d = 0;
	*d1 = 0;
	for(int i = 0; i < b; i++){
		d += a[i];
		if(d > c){
			c = d;
			*d2 = i;
		}
		if(d < 0){
			d = 0;
			*d1 = i + 1;
		}
	}
	return c;
}
int main(){
	int a[] = {2,4,-7,5,2,-1,2,-4,3};
	int b, c;
	printf("b:%d c:%d %d\n", b, c, f2(a, 9, &b, &c));
}

另外的兩種方法

最優起點

算法思想:設a[i]爲和最大序列的起點,則如果a[i]是負的,那麼它不可能代表最優序列的起點,因爲任何包含a[i]作爲起點的子序列都可以通過a[i+1]作起點而得到改進。參考(窗雨樹雪)

3、大數相乘

#include <iostream>
#include <sstream>
#include <string>
using namespace std;
///字符串轉換成int 相乘 
string f1(string a, string b){
	stringstream c;
	int aa;
	int bb;
	string cc;
	c << a;
	c >> aa;
	c.clear();
	c << b;
	c >> bb;
	c.clear();
	c << aa * bb;
	c >> cc;
	return cc;
}
//字符串轉換成int 相加 
string f4(string a, string b){
	stringstream c;
	int aa;
	int bb;
	string cc;
	c << a;
	c >> aa;
	c.clear();
	c << b;
	c >> bb;
	c.clear();
	c << aa + bb;
	c >> cc;
	return cc;
}
// 在後面填0 
string f3(int b){
	if(b == 0){
		return "";
	}
	if(b == 1){
		return "0";
	}
	return f3(b / 2) + f3(b / 2) + f3(b % 2);
}
//不是分成兩段,從低位起每8 位一段 
string add(string a, string b){
//	cout << a << " " << b << endl;
	if(a.length() <= 8 && b.length() <= 8){
		return f4(a, b);
	}
	string a1 = "0";
	string a2 = a;
	if(a.length() > 8){
		a1 = a.substr(0, a.length() - 8);
		a2 = a.substr(a.length() - 8);
	}
	
	string b1 = "0";
	string b2 = b;
	if(b.length() > 8){
		b1 = b.substr(0, b.length() - 8);
		b2 = b.substr(b.length() - 8);
	}
	
	string c = add(a2, b2);
	while(c.length() < 8) c = "0" + c;
	if(c.length() > 8) return add(add(a1, b1), "1") + c.substr(1);
	return add(a1, b1) + c;
}
string f(string a, string b){
	if(a.length() < 5 && b.length() < 5){
		return f1(a, b);
	}
	if(a.length() > 4){
		int c = a.length() / 2;
		string d = a.substr(0, c);
		string e = a.substr(c);
		return add(f(d, b) + f3(e.length()), f(e,b));
	}
	return f(b, a);
}
int main(){
//	cout << add("111111111111111", "111111111111111111");
	cout << f("1234567890987654321666", "1234567890123456789555") << endl;
} 

4、城牆刷漆

X國的一段古城牆的頂端可以看成 2*N個格子組成的矩形(如圖所示)
現需要把這些格子刷上保護漆。


你可以從任意一個格子刷起,刷完一格,可以移動到和它相鄰的格子(對角相鄰也算數),但不能移動到較遠的格子(因爲油漆未乾不能踩!)


比如:a d b c e f 就是合格的刷漆順序。
c e f d a b 是另一種合適的方案。


當已知 N 時,求總的方案數。當N較大時,結果會迅速增大,請把結果對 1000000007 (十億零七) 取模。
輸入數據爲一個正整數(不大於1000)
輸出數據爲一個正整數。


例如:
用戶輸入:
2
程序應該輸出:
24


再例如:
用戶輸入:
3
程序應該輸出:
96


再例如:
用戶輸入:
22
程序應該輸出:
359635897


reference: 於航

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
long long int M = 1000000007;
long long f1(int n){
	if(n == 1) return 1;
	return f1(n - 1) * 2 % M;
}
long long f2(int n){
	if(n == 1){
		return 1;
	}
	if(n == 2){
		return 6;
	}
	return (f1(n) + 2 * f2(n - 1) + 4 * f2(n - 2)) % M;
}

long long f3(int a, int b){
	return (f1(a) * f2(b-a) * 2 % M + f1(b-a+1) * f2(a-1) * 2 % M) * 2 % M;
}

long long f(int n){
	long long a = 0;
	if(n == 1){
		return 2;
	}
	a += f2(n) * 4 % M;
	for(int i = 2; i < n; i++){
		a = (a + f3(i, n))% M;
	}
	return a;
}

int main(){
//	printf("%d", M);
	for(int i = 1; i < 30; i++){
		printf("%d\n", f(i));
	}
}

5、環形塗色



如圖,組成環形的格子需要塗3種顏色。
它們的編號分別是1~14
相鄰的格子不能用相同的顏色。
塗色方案的數目是:24576


當格子數目爲50的時候,求塗色方案總數。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int f1(int n, int * a){ //f(n)中減去最後一個和第一個重複的,此時有n-1個格子,相當於減去f(n-1)
	if(a[n] != 0) return a[n];
	if(n == 1) return 1;
	if(n == 2) return 6;
	if(n == 3) return 6;
	a[n] = 3 * pow(2, n - 1) - f1(n - 1, a);
	return a[n];
}
int f(int n, int * a){
	if(a[n] != 0) return a[n];
	if(n == 1) return 1;
	if(n == 2) return 6;
	if(n == 3) return 6;
	a[n] = 2 * f(n - 2, a) + f(n - 1, a);
	return a[n];
}
int main(){
	int a[60];
	memset(a, 0, 60 * 4);
	for(int i = 1; i < 20; i++){
		printf("%d: %d\n", i, f1(i, a));
	}
}

f(n) = f(n -1) + 2 * f(n - 2);

 遞推關係:

1、假設第n-1塊的顏色和第1塊不同,那前n-1個方塊就是f(n-1)問題。由於第n塊的顏色既不能和第n-1塊顏色相同,也不能第1塊相同,那麼第n塊只能選擇剩下的那種顏色,唯一的一種選法。這時有f(n-1)種情況。

2、假設第n-1塊的顏色和第1塊是相同的,那知道第n-2塊的顏色必定和第1塊不同了,那前n-2個方塊就是f(n-2)問題。此時,第n塊有兩種選擇,只要顏色和第n-1塊的顏色不同即可。這時有2*f(n-2)種情況。

上面兩種情況綜合起來,就得到了遞推關係:  f(n) = f(n-1) + 2*f(n-2)

reference: ojshilu

發佈了17 篇原創文章 · 獲贊 3 · 訪問量 9253
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章