Ex1-10 平均情况下的时间复杂度
T
a
v
g
(
N
)
=
∑
I
∈
D
N
P
(
I
)
T
(
N
,
I
)
≤
∑
I
∈
D
N
P
(
I
)
max
I
′
∈
D
n
T
(
N
,
I
′
)
=
T
(
N
,
I
∗
)
∑
I
∈
D
N
P
(
I
)
=
T
(
N
,
I
∗
)
=
T
m
a
x
(
N
)
T_{avg}(N)=\sum_{I\in D_N}P(I)T(N,I)\le \sum_{I\in D_N}P(I)\max_{I'\in D_n} T(N,I') \\=T(N,I^*)\sum_{I\in D_N}P(I) \\=T(N,I^*)=T_{max}(N)
Tavg(N)=I∈DN∑P(I)T(N,I)≤I∈DN∑P(I)I′∈DnmaxT(N,I′)=T(N,I∗)I∈DN∑P(I)=T(N,I∗)=Tmax(N)
因此
T
m
a
x
(
N
)
=
Ω
(
T
a
v
g
(
N
)
)
=
Ω
(
θ
(
f
(
n
)
)
=
Ω
(
f
(
n
)
)
T_{max}(N)=\Omega(T_{avg}(N))=\Omega(\theta(f(n))=\Omega(f(n))
Tmax(N)=Ω(Tavg(N))=Ω(θ(f(n))=Ω(f(n))
Ex2-30 石油管道
某石油公司计划建造一晶由东向西的主输油管道。诙管道暨穿过一个有n门油井的油田。从每口油井都要有一条输油管道沿最短路经(或南或北)与主管道相连。如果给定n口油井的位置,即它们的x坐标和y坐标,应如何确定主管道的最优位置,即使各油井到主管道之间的输油管道长度总和最小的位置?证明可在线性时间内确定主管道的最优位置。
O
(
n
)
O(n)
O(n)查找第k小的算法如下,所以只需要调用
R
a
n
d
o
m
i
z
e
d
S
e
l
e
c
t
(
y
[
]
,
0
,
n
−
1
,
(
n
+
1
)
/
2
)
RandomizedSelect(y[], 0, n-1, (n+1)/2)
RandomizedSelect(y[],0,n−1,(n+1)/2)。
该算法实际上是模仿快速排序算法设计出来的的。其基本思想也是对输入数组进行递归划分。与快速排序算法不间的是,它只对划分出的子数组之一进行递归处理。
template <class Type>
Type RandomizedSelect(Type a[], int p, int r, int k){
if (p==r) return a[p];
int i = RandomizedPartition(a, p, r);
j = i-p+1;
if (k <= j) return RandomizedSelect(a, p, i, k);
else return RandomizedSelect(a, i+1, r, k-j);
}
int RandomizedPartition(Type a[], int p, int r){
int i = p;
int j = r+1;
int rand = Random(p, r);
Swap(a[p], a[rand]);
Type x = a[p];
while(true){
while (a[++i] < x);
while (a[--j] > x);
if (i>=j) break;
Swap(a[i], a[j]);
}
a[p] = a[j];
a[j] = x;
return j;
}
Ex2-33 马遍历
考虑国际象棋棋盘上某个位置的一只马,它是否可能只走63步,正好走过除起点外的其他63个位置各一次?如果有种这样的走法,则称所走的这条路线为一条马的周游路线。试设计一个分治算法找出这样的一条马的周游路线。
定义 1:如果能从棋盘上最后遍历的一个点回到第一个点,则称这种马的遍历是闭合的。
定义 2:如果马的遍历路径包含下图中的所有路径,则称这种马的遍历是结构性的。
bool Knight::comp(int m, int n, int offx, int offy){
int m1, m2, n1, n2;
int x[8], y[8], p[8];
if (odd(m) || odd(n) || m-n>2 || n-m>2 || m< 6 || n < 6)return true;
if (m < 12 || n<12){base(m, n, offx, offy); return 0;}
m1 = m/2;
if (m%4 > 0) --m1;
m2 = m-m1;
n1 = n/2;
if (n%4 > 0) --n1;
n2 = n-n1;
//分割步
comp(m1, n1, offx, offy);
comp(m1, n2, offx, offy+n1);
comp(m2, n1, offx+m1, offy);
comp(m2, m2, offx+m1, offy+n1);
//合并步
x[0] = offx+m1-1;y[0] = offy+n1 - 3;
x[1] = x[0]-1;y[1] = y[0]+2;
x[2] = x[1]-1;y[2] = y[1]+2;
x[3] = x[2]+2;y[3] = y[2]-1;
x[4] = x[3]+1;y[4] = y[3]+2;
x[5] = x[4]+1;y[5] = y[4]-2;
x[6] = x[5]+1;y[6] = y[5]-2;
x[7] = x[6]-2;y[7] = y[6]+1;
for (int i = 0;i < 8;++i) p[i] = pos(x[i], y[i], n);
for (int i = 1;i < 8; i += 2){
int j1 = (i+1)%8, j2 = (i+2)%8;
if (link[x[i]][y[i]].x == p[i-1])
link[x[i]][y[i]].x = p[j1];
else
link[x[i]][y[i]].y = p[j1];
if (link[x[j1]][y[j1]].x == p[j2])
link[x[j1]][y[j1]].x = p[i];
else
link[x[j1]][y[j1]].y = p[i];
}
}
void Knight::base(int m, int n, int offx, int offy){
if (m==6&&n==6) build(m, n, offx, offy, N, b66);
if (m==6&&n==8) build(m, n, offx, offy, N, b68);
if (m==8&&n==6) build(m, n, offx, offy, N, b86);
if (m==8&&n==10) build(m, n, offx, offy, N, b810);
if (m==10&&n==8) build(m, n, offx, offy, N, b108);
if (m==10&&n==10) build(m, n, offx, offy, N, b1010);
if (m==10&&n==12) build(m, n, offx, offy, N, b1012);
if (m==12&&n==10) build(m, n, offx, offy, N, b1210);
}
void Knight::build(int m, int n, int offx, int offy, int col, grid *b){
int i, p, q, k = m*n;
for (i = 0;i < k;++i){
int x1 = offx+b[i].x, y1 = offx+b[i].y;
int x2 = offx+b[(i+1)%k].x, y2 = offy+b[(i+1)%k].y;
p = pos(x1, y1, col);
q = pos(x2, y2, col);
link[x1][y1].x = q;
link[x2][y2].y = p;
}
}
int Knight::pos(int x, int y, int col){
return col*x + y;
}
Ex2-34 格雷码
分治法构造格雷码
void gray(int n){
if (n==1){
a[1] = 0;
a[2] = 1;
return;
}
gray(n-1);
for (int k = 1<<(n-1),i=k;i>0;--i){
a[2*k-i+1] = k + a[i];
}
}
void out(int n){
char str[32];
int m = 1<<n;
for (int i = 1;i <= m;++i){
_itoa(a[i], str, 2);
int len = strlen(str);
for (int j = 0;j < n-len;++j) cout << '0';
cout << str << " ";
}
cout << endl;
}
T
(
n
)
=
{
1
n
=
1
T
(
n
−
1
)
+
2
n
−
1
n
>
1
T(n)=\begin{cases} 1 & n=1 \\ T(n-1) + 2^{n-1} & n >1 \end{cases}
T(n)={1T(n−1)+2n−1n=1n>1
解此递归方程的,算法的时间复杂度为
O
(
2
n
)
O(2^n)
O(2n)
Ex2-35 日程安排
设n个运动员要进行网球循环赛。设计一个满足以下要求的比赛日程表:
(1) 每个选手必须与其他n-1个选手各赛一次。
(2)每个选手一天只能赛一次。
(3)当n是偶数时,循环赛进行n-1天。当n是奇数时,循环赛进行n天
void tournament(int n){
if (n==1){
a[1][1] = 1;
return;
}
if (odd(n)){
tournament(n/2);
makecopy(n);
}
}
bool odd(int n){
return n & 1;
}
void makecopy(int n){
if (n/2>1 && odd(n/2))
copyodd(n);
else
copy(n);
}
void copyodd(int n){
int m = n/2;
for (int i = 1;i <= m;++i)
{
b[i] = m+i;
b[m+i] = b[i]
}
for (int i = 1;i <= m; ++i){
for (int j = 1;j <=m+1;++j){
if (a[i][j] > m){
a[i][j] = b[i];
a[i+m][j] = (b[i]+m)%n;
}
else{
a[i+m][j] = a[i][j]+m;
}
}
for (int j = 2;j <=m;++j){
a[i][m+j] = b[i+j-1];
a[b[i+j-1]][m+j] = i;
}
}
}
Ex3-3 作业调度
对于给定的2台处理机A和B处理n个作业,找出一个最优调度方案,使两台机器处理完这n个作业的时间最短。
分析:
(1)计算出
m
=
max
{
max
1
≤
i
≤
n
{
a
i
}
,
max
1
≤
i
≤
n
{
b
i
}
}
m=\max\{\max_{1\le i\le n}\{a_i\},\max_{1\le i\le n}\{b_i\}\}
m=max{1≤i≤nmax{ai},1≤i≤nmax{bi}}
(2)设布尔量p(i,j,k)表示前k个作业可以在处理机A用时不超过i,在处理机B用时不超过j时间内完成。动态转移方程如下
p
(
i
,
j
,
k
)
=
p
(
i
−
a
k
,
j
,
k
−
1
)
∣
p
(
i
,
j
−
b
k
,
k
−
1
)
p(i,j,k)=p(i-a_k,j,k-1) | p(i,j-b_k,k-1)
p(i,j,k)=p(i−ak,j,k−1)∣p(i,j−bk,k−1)
(3)最短时间为:
min
0
≤
i
≤
m
n
,
0
≤
j
≤
m
n
,
p
(
i
,
j
,
n
)
=
t
r
u
e
{
m
a
x
(
i
,
j
)
}
\min_{0\le i \le mn,0\le j \le mn,p(i,j,n)=true}\{max(i,j)\}
0≤i≤mn,0≤j≤mn,p(i,j,n)=truemin{max(i,j)}
code:
void dyna(){
for (int i = 0;i <= mn;++i)
for (int j = 0;j <=mn;++j){
p[i][j][0] = true;
for (int k = 1;k <=n;++k)p[i][j][k] = false;
}
for (int k = 1;k <= n;++k)
for (int i = 0;i <= mn;++i)
for (int j = 0;j <= mn;++j){
if (i >= a[k-1])
p[i][j][k] = p[i-a[k-1]][j][k-1];
if (j >= b[k-1]
p[i][j][k] = p[i][j-b[k-1]][k-1];
}
int opt = mn;
for (int i = 0;i <= mn;++i)
for (int j =0; j <= mn;++j)
if (p[i][j][n]){
opt = min(opt, max(i,j));
}
}
时间复杂度: O ( m 2 n 3 ) O(m^2n^3) O(m2n3)
Ex3-7 漂亮打印
void BeautifulPrint(){
c[0] = 0;
l[0] = maxint;
for (int i = 1;i <= n;++i){
int j = i;
extra = M-l[j];
while (extra >= 0){
if (i == n)
lc = 0;
else
lc = extra * extra * extra;
if (c[i]>c[j-1]+lc){
c[i] = c[j-1] + lc;
p[i] = j-1;
}
--j;
extra = extra - l[j] - 1
}
}
}
最后一行从p[n]+1开始打印,倒数第二行从p[p[n]]+1开始打印。
时间复杂度:
O
(
M
n
)
O(Mn)
O(Mn)
空间复杂度:
O
(
n
)
O(n)
O(n)
Ex3-9 石子合并
在一个圆形操场的四周摆放着n堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的两堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分,并分析算法的复杂性
int MinStoneMerge(vector<int> a){
int n = a.size()-1;
for (int i = 1;i < n;++i) a.push_back(a[i]);
int s[2*n] = {0};
for (int i = 1;i <= 2*n-1;++i)
s[i] = s[i-1]+a[i];
int m[2*n][2*n] = {0};
for (int l = 2;l <= n;++l)
for (int i = 1;i <= 2*n-l;++i){
int j = i+l-1;
m[i][j] = INT_MAX;
for (int k = i;k < j;++k)
m[i][j] = min(m[i][j], m[i][k]+m[k+1][j]+s[j]-s[i-1]);
}
int ret = INT_MAX;
for (int i = 1;i <= n;++i)
ret = min(ret, m[i][i+n-1]);
return ret;
}
int MaxStoneMerge(vector<int> a){
int n = a.size()-1;
for (int i = 1;i < n;++i) a.push_back(a[i]);
int s[2*n] = {0};
for (int i = 1;i <= 2*n-1;++i)
s[i] = s[i-1]+a[i];
int m[2*n][2*n] = {0};
for (int l = 2;l <= n;++l)
for (int i = 1;i <= 2*n-l;++i){
int j = i+l-1;
m[i][j] = INT_MIN;
for (int k = i;k < j;++k)
m[i][j] = max(m[i][j], m[i][k]+m[k+1][j]+s[j]-s[i-1]);
}
int ret = INT_MIN;
for (int i = 1;i <= n;++i)
ret = max(ret, m[i][i+n-1]);
return ret;
}
Ex3-21 最大子立方体
解析:此问题可以看做最大子段和在三维上的推广,详见课本pdf 67
int MaxSum(int n, int *a){
int sum = 0, b = 0;
for (int i = 1;i <= n;++i){
if (b>0)
b += a[i];
else
b = a[i];
sum = max(sum, b);
}
return sum;
}
int MaxSum2(int m, int n, int **a){
int sum = 0;
int *b = new int[n+1];
for (int i = 1;i <=m;++i){
memset(b, 0, sizeof(b));
for (int j = i;j <=m;++j){
for (int k = 1;k <= n;++k) b[k] += a[j][k];
sum = max(sum, MaxSum(n, b));
}
}
return sum;
}
int MaxSum3(const vector<matrix<int> > &a){
int sum = 0;
int m = a.size(), n = a[0].rows(), p = a[0].cols();
int b[n][p] = {0};
for (int i = 0;i <m;++i){
memset(b, 0, sizeof(b));
for (int j = i;j < m;++j){
for (int k = 0;k < n;++k)
for (int t = 0;t < p;++t)
b[k][t] += a[j][k][t];
sum = max(sum, MaxSum2(n, p, b));
}
}
return sum;
}
Ex4-2 活动安排
Ex4-26 数列极差
贪心策略:
max: a,b每次取数列最小的两个数
min:a,b每次取数列最大的两个数
code:
int max(int *a, int n)
{
priority_queue<int> q;
int i;
for(i=0; i<n; i++)
q.push(a[i]);
int data1, data2, data;
while(q.size()>=2) //一直合并下去,直到队列中只剩下一个数
{
data1 = q.top(); q.pop();
data2 = q.top(); q.pop();
data = data1 * data2 + 1;
q.push(data);
}
data = q.top();
q.pop();
return data;
}
int min(int *a, int n)
{
priority_queue<int, vector<int>, greater<int> > q;
int i;
for(i=0; i<n; i++)
q.push(a[i]);
int data1, data2, data;
while(q.size()>=2) //一直合并下去,直到队列中只剩下一个数
{
data1 = q.top(); q.pop();
data2 = q.top(); q.pop();
data = data1 * data2 + 1;
q.push(data);
}
data = q.top();
q.pop();
return data;
}
---------------------
作者:谛听-
来源:CSDN
原文:https://blog.csdn.net/u012319493/article/details/50001057
版权声明:本文为博主原创文章,转载请附上博文链接!
Dijkstra Algorithm
迭代 | S | u | dist[2] | dist[3] | dist[4] | dist[5] |
---|---|---|---|---|---|---|
初始 | 1 | - | 10 | MAX | 30 | 100 |
1 | 1,2 | 2 | 10 | 60 | 30 | 100 |
2 | 1,2,4 | 4 | 10 | 50 | 30 | 90 |
3 | 12,4,3 | 3 | 10 | 50 | 30 | 60 |
4 | 1,2,4,3,5 | 5 | 10 | 50 | 30 | 60 |
code:
template<class Type>
void Dijkstra(int n, int v, Type dist[], int prev[], Type **c)
{
bool s[n+1] = {false};
for (int i = 1;i <= n;++i){
dist[i] = c[v][i];
if (dist[i] == INT_MAX) prev[i] = 0;
else prev[i] = v;
}
dist[v] = 0;s[v] = true;
for (int i =1;i < n;++i){
int temp = INT_MAX;
int u = v;
for (int j = 1;j <= n;++j){
if ((!s[j]) && (dist[j]<temp)){
u = j;
temp = dist[j];
}
}
s[u] = true;
for (int j = 1;j <= n;++j)
if ((!s[j])&&(c[u][j]<maxint)){
Type newdist = dist[u] + c[u][j];
if (newdist < dist[j]){
dist[j] = newdist;
prev[j] = u;
}
}
}
}
时间复杂度: O ( n 2 ) O(n^2) O(n2)
Ex5-4 01背包
template <class Typew, class Typep>
class Knap{
friend Typep Knapsack(Typep*, Typew*, Typew, Typew, int, int[]);
private:
Typep Bound(int i);
void Backtrack(int i);
Typew c;//背包容量
int n;//物品数
int *x;//当前解
int *bestx;//当前最优解
Typew * w;//物品重量数组
Typep * p;//物品价值数组
Typew cw;//当前重量
Typep cp;//当前价值
Typep bestp;//当前最有价值
}
template <class Typew, class Typep>
Type Knap<Typew, Typep>::Bound(int i){
Typew left = c-cw;
TYpep b = cp;
while (i <=n && w[i] <= left){
left -= w[i];
b += p[i];
++i;
}
if (i <= n) b += p[i]/w[[i] * left;
return b;
}
class Object{
friend int Knapsack(int *, int*, int, int);
public:
int operator <= (Object a) const{
return (d >= a.d);
}
private:
int id;
float d;
};
template <class Typew, Typep>
void Knap<Typew, Typep>::Backtrack(int i){
if (i>n){
for (int j = 1;j <= n;++i) bestx[j] = x[j];
bestp = cp;
return;
}
if (cw + w[i] <= c){
x[i] = 1;
cw += w[i];
cp += p[i];
Backtrack(i+1);
x[i] = 0;
cw -= w[i];
cp -= p[i];
}
if (Bound(i+1) > bestp)
Backtrack(i+1);
}
template<class Typew, class Typep>
Typep Knapsack(Typep p[], Typew w[], Typew c, int n, int bestx[]){
Typew W = 0;
Typep P = 0;
Object *Q = new Object[n];
for (int i = 1;i <= n;++i){
Q[i-1].id = i;
Q[i-1].d = 1.0 * p[i]/w[i];
P += p[i];
W += w[i];
}
if (W <= c) return P;
Sort(Q, n);
Knap<Typew, Typep> k;
k.p = new Typep[n+1];
k.w = new Typew[n+1];
k.x = new int[n+1];
for (int i = 1;i<=n;++i){
k.p[i] = p[Q[i-1].id];
k.w[i] = w[Q[i-1].id];
k.x[i] = 0;
}
k.cp = 0;
k.cw = 0;
k.c = c;
k.n = n;
k.bestp = 0;
k.bestx = bestx;
k.Backtrack(1);
for (int i =1;i <=n;++i) k.x[i] = k.bestx[i];
for (int i =1;i <= n;++i)k.bestx[Q[i-1].id] = k.x[i];
delete []Q;
delete []k.w;
delete []k.p;
delete []k.x;
return k.bestp;
}
Ex5-5 最大团问题
code
class Clique{
void Backtrack(int i);
int **a,//图G的邻接矩阵
n,//图G的顶点数
*x,// 当前解
*bestx,//当前最优解
cn,//当前顶点数
bestn;//当前最大顶点数
}
void Clique::iterClique(){
for (int i = 0;i <= n;++i) x[i] = 0;
i = 1;
while (true){
while (i <= n && ok(i)){
x[i++] = 1;
++cn;
}
if (i >= n){
for (int j = 1;j <=n;++j) bestx[j] =x[j];
bestn = cn;
}
else
x[i++] = 0;
while (cn+n-i <= bestn){
--i;
while (i && !x[i]) --i;
if (i==0) return ;
x[++i] = 0;
--cn;
}
}
}
bool Clique::ok(int i){
for (int j = 1;j < i;++j)
if (x[j] && a[i][j]==0)
return false;
return true;
}
时间复杂度: O ( 2 n ) O(2^n) O(2n)
Ex-5-14 运动员最佳匹配
class pref{
private:
int best;
int n;
int *r;
int **p, **q;
}
void pref::Backtrack(int t){
if (t > n){
Compute();
}
else{
for (int j = t;j <= n;++j){
swap(r[t], r[j]);
Backtrack(t+1);
swap(r[t], r[j]);
}
}
}
void pref::Compute(void){
int temp = 0;
for (int i = 1; i <= n;++i){
temp += p[i][r[i]]*q[r[i]][i];
}
if (temp > best){
best = temp;
for (int i = 1;i <=n ;++i)
bestr[i] = r[i];
}
}
Ex5-21 罗密欧与朱丽叶
void search(int dep, int x, int y, int dir){
if (dep == m*n-k && x==x1 && y==y1 && dirs <= best){
if (dirs < best){
best = dirs;
count = 1;
save();
}
else{
++count;
}
return;
}
if (dep==m*n-k || x==x1&&y==y1 || dirs>best) return;
else{
for (int i = 1;i <= 8;++i)
if (stepok(x+dx[i], y+dy[i])){
board[x+dx[i]][y+dy[i]] = dep+1;
if (dir != i) ++dir;
search(dep+1, x+dx[i], y+dy[i], i);
if (dir != i) --dir;
board[x+dx[i]][y+dy[i]] = 0;
}
}
}
bool stepok(int x, int y){
return x>0 && x<=n && y>0 &&y<=m && board[x][y] = 0;
}
void save(){
for (int i = 1;i <=n;++i)
for (int j = 1;j < m;++j){
bestb[i][j] = board[i][j];
}
}