几个经典算法


蛮力算法

子集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<iostream>
using namespace std;
#define MAX 1000
int main() {
int n;
int a[MAX];
int tol;//子集的个数
n=4;
for(int i=0; i<n; i++) {
cin>>a[i];
}
tol=(1<<n)-1; //子集的个数
for(int i=0; i<=tol; i++) {
for(int j=0; j<n; j++)
if(i&(i<<j)) cout<<a[j]; //i<<j相当于对每一个进行标记
cout<<" "<<endl;
}
}


递归算法

1.输出全排列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<iostream>
using namespace std;
void Perm(int list[],int k,int m) {
if(k==m) {
for(int i=0; i<=m; i++)
cout<<list[i]<<" ";
cout<<endl;
} else {
for(int j=k; j<=m; j++) {
swap(list[k],list[j]);
Perm(list,k+1,m);
swap(list[k],list[j]);
}
}
}
int main() {
int list[]= {1,2,3,4,5};
Perm(list,0,3);
}

//正整数n的划分算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
using namespace std;
int split(int n,int m)
{
if(n==1||m==1) return 1;
else if (n<m) return split(n,n);
else if(n==m) return split(n,n-1)+1;
else return split(n,m-1)+split(n-m,m);
}
int main()
{
int n;
while (cin>>n)
cout<<split(n, n)<<endl;
return 0;
}
//对一个段进行递归调用
return select(j+1, right, k-j+left-1);
else return select(left, j-1, k);
}
int main()
{
int n, k;
while (cin>>n>>k)
{
for (int i=0; i<n; i++)
cin>>a[i];
cout<<select(0, n-1, k)<<endl;
}
return 0;
}

//半数集问题的递归算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<iostream>
using namespace std;
int a[1001];
int comp(int n)
{
int ans=1;
if(a[n]>0)return a[n];
for(int i=1;i<=n/2;i++)
ans+=comp(i);
a[n]=ans;
return ans;
}
int main()
{
int n;
while(cin>>n)
{
memset(a,0,sizeof(a));
a[1]=1;
cout<<comp(n)<<endl;
}
return 0;
}


分治算法

选择问题
//采用分治策略找出第k小元素的算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <iostream>
using namespace std;
#define NUM 1001
int a[NUM];
int select(int left, int right, int k)
{
//找到第k小的元素
if (left >= right) return a[left];
int i = left;
int j = right+1;
//把最左边的元素作为分界数据
int pivot = a[left];
while (true)
{
do {
i = i+1;
} while (a[i] < pivot);
do {
j = j-1;
} while (a[j] > pivot);
if (i >= j) break;
swap(a[i], a[j]);
}
if (j-left+1 == k) return pivot;
a[left] = a[j];
a[j] = pivot;
if (j-left+1 < k)
return select(j+1,right,k-j+left-1);
else return select(left,j-1,k);
}
选择第K个大的数
#include<iostream>
using namespace std;
void swap(int *a, int *b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
int partition(int arr[], int left, int right, int pivotIndex)
{
int storeIndex = left;
int pivotValue = arr[pivotIndex];
int i;
swap(&arr[pivotIndex],&arr[right]);
for (i = left; i < right; i ++)
{
if (arr[i] > pivotValue)
{
swap(&arr[i],&arr[storeIndex]);
storeIndex++;
}
}
swap(&arr[storeIndex],&arr[right]);
return storeIndex;
}
int findKMax(int arr[], int left, int right, int k)
{
int nRet;
int pivotIndex = left + 1;
nRet = partition(arr,left,right,pivotIndex);
if (nRet < k)
{
return findKMax(arr,nRet+1,right,k);
}
else if (nRet > k)
{
return findKMax(arr,left,nRet-1,k);
}
return nRet;
}
int main()
{
int i,k,nRet;
int arr[] = {8,3,4,1,9,7,6,10};
scanf("%d",&k);
nRet = findKMax(arr,0,7,k-1);
printf("The Kth Max Number locate in %d is :%d\n",nRet,arr[nRet]);
for (i = 0; i < 8; i++)
{
printf("%3d",arr[i]);
}
return 0;
}

/循环赛程表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <stdio.h>
#define MAX 100
int a[MAX][MAX];
void Copy(int tox, int toy, int fromx, int fromy, int r)
{
for (int i=0; i<r; i++)
for (int j=0; j<r; j++)
a[tox+i][toy+j] = a[fromx+i][fromy+j];
}
//构造循环赛日程表,选手的数量n=2^k
void Table(int k)
{
int i, r;
int n = 1 << k;
//构造正方形表格的第一行数据
for (i=0; i<n; i++)
a[0][i] = i + 1;
//采用分治算法构造整个循环日程赛表
for (r=1; r<n; r<<=1)
for (i=0; i<n; i+=2*r)
{
Copy(r, i + r, 0, i, r);
Copy(r, i, 0, i + r, r);
}
}
void Out(int n)
{
for (int i=0; i<n; i++)
{
for (int j=0; j<n; j++)
printf("%3d", a[i][j]);
printf("\n");
}
printf("\n");
}
int main()
{
int k;
while (scanf("%d", &k) && k)
{
int n = 1 << k;
Table(k);
Out(n);
}
return 0;
}


动态规划

矩阵链乘积

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<iostream>
using namespace std;
int m[100][100];
int p[100],s[100][100];
int k;
int TraceBack(int i,int j) {
if(m[i][j]>0) return m[i][j];
if(i==j) return 0;
int u=TraceBack(i,i)+TraceBack(i+1,j)+p[i-1]*p[k]*p[j];
s[i][j]=i;
for(int k=i+1; k<j; k++) {
int t=TraceBack(i,k)+TraceBack(k+1,j)+p[i-1]*p[k]*p[j];
if(t<u) {
u=t;
s[i][j]=k;
}
m[i][j]=u;
return u;
}
}

最多单减子序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<iostream>
using namespace std;
#define MAX 1000
int a[MAX] = {2,1,3};
int select(int left,int right,int k) {
if(left>=right) return a[left];
int i =left;
int j = right+1;
int pivot = a[left]; //把第一个设为界点
while(true) {
do {
i++;
} while(a[i]<pivot);
do {
j--;
} while(a[j]>pivot);
if(i>=j) break;
swap(a[i],a[j]);
}
if(j-left+1==k) return pivot; //该界点就是要找的数
a[left]=a[j];
a[j]=pivot;
if(j-left+1<k) return select(j+1, right, k-j+left-1);
else return select(left,j-1,k);
}
int main() {
// int a[3] = {2,1,3};
cout<<select(0,2,2);
}

//计算0-1背包的动态规划算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include<ctime>
using namespace std;
#define NUM 50
#define CAP 1500
int v[NUM];
int w[NUM];
int p[NUM][CAP];
//形参c是背包的容量w,n是物品的数量
void knapsack(int c, int n)
{
int jMax=min(w[n]-1,c);
for( int j=0; j<=jMax; j++)
p[n][j]=0;
for( int j=w[n]; j<=c; j++)
p[n][j]=v[n];
for( int i=n-1; i>1; i--)
{
jMax=min(w[i]-1,c);
for( int j=0; j<=jMax; j++)
p[i][j]=p[i+1][j];
for(int j=w[i]; j<=c; j++)
p[i][j]=max(p[i+1][j], p[i+1][j-w[i]]+v[i]);
}
p[1][c]=p[2][c];
if (c>=w[1])
p[1][c]=max(p[1][c], p[2][c-w[1]]+v[1]);
}
void traceback( int c, int n, int x[ ])
{
for(int i=1; i<n; i++)
{
if (p[i][c]==p[i+1][c]) x[i]=0;
else { x[i]=1; c-=w[i]; }
}
x[n]=(p[n][c])? 1:0;
}
int main ()
{
int x[NUM];
int W;
int n;
while (scanf("%d", &W) && W)
{
scanf("%d", &n);
for (int i=1; i<=n; i++)
scanf("%d%d", &w[i], &v[i]);
memset (p, 0, sizeof(p));
knapsack(W, n);
printf("%d\n", p[1][W]);
traceback(W, n, x);
for (int i=1; i<=n; i++)
if (x[i]) printf("%d ", i);
printf("\n");
}
return 0;
}

//计算最大字段和的动态规划算法的最优解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
#define NUM 1001
int a[NUM];
int MaxSum(int n, int &besti, int &bestj)
{
int sum=0;
int b=0;
int begin = 0;
for (int i=1;i<=n;i++)
{
if (b>0) b+=a[i];
else {b=a[i];begin = i;}
if (b>sum)
{
sum = b;
besti = begin;
bestj = i;
}
}
return sum;
}
int main()
{
int n;
int besti, bestj;
while (scanf("%d", &n) && n)
{
besti = 0;
bestj = 0;
for (int i=1; i<=n; i++)
scanf("%d", &a[i]);
printf("%d\n", MaxSum(n, besti, bestj));
printf("From %d to %d\n", besti, bestj);
}
return 0;
}


贪心算法

//删数问题 ,找最近下降点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream>
#include<String>
using namespace std;
int main() {
string a;
int k;
cin>>a>>k;
if(k>=a.size()) a.erase();
else while(k>0) {
int i;
for(i=0; (i<a.size()-1)&&a[i]<=a[i+1]; i++);
a.erase(i,1);
k--;
}
while(a.size()>1 && a[0]=='0')
a.erase(0,1);
cout<<a<<endl;
}

删数问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<iostream>
#include<string>
using namespace std;
int main()
{
string n;
int s,i,x,l,m;
while(cin>>n>>s)
{
i=-1,m=0,x=0;
l=n.length();
while(x<s&&m==0)
{
i++;
if(n[i]>n[i+1])//出现递减,删除递减的首数字
{
n=n.erase(i,1);
x++;// x统计删除数字的个数
i=-1;//从头开始查递减区间
}
if(i==l-x-2&&x<s)
m=1;//已经无递减区间,m=1脱离循环
}
cout<<n.substr(0,l-s+x)<<endl;//只打印剩下的左边l-(s-x)个数字
}
return 0;
}


回溯算法

轮船装载(回溯)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<iostream>
using namespace std;
#define NUM 100 //解空间树
int n; //集装箱数量
int c; //轮船装在数量
int w[NUM];//集装箱重量数组
int x[NUM];//解向量
int r; //剩余集装箱重量
int cw; //当前轮船载重量
int bestw; //当前最优载重量
int bestx[NUM];//当前最优解
void Backtrack(int t) {
//到达叶子节点
if(t>n) {
if(cw>bestw) { //更新最优解
for(int i=1; i<=n; i++)
bestx[i] = x[i];
bestw = cw;
}
return;
}
//更新剩余集装箱的重量
r-= w[t];
//搜索左子树
if(cw+w[t]<=c) {
x[t]=1;
\
cw+=w[t];
Backtrack(t+1);
cw-=w[t];//恢复 状态
}
//搜索右子树
if(cw+r>bestw) {
x[t]=0;
Backtrack(t+1);
}
r+= w[t];//恢复状态
}

N皇后问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include<iostream>
#include<cmath>
using namespace std;
#define NUM 20
int n=8;
int x[NUM]; //记录解向量,列号
int sum=0; //解的个数
inline bool Place(int t) {
int i;
for(i=1; i<t; i++) {
if((abs(t-i) == abs(x[i]-x[t])) || (x[i]==x[t]))
return false;
}
return true; //只要不满足循环就返回true
}
void Backtrack(int t) {
int i;//叶子节点
if(t>n) {
sum++;
for(i=1; i<=n; i++) {
cout<<x[i];
}
cout<<endl;
} else {
for(i=1; i<=n; i++) {
x[t]=i;
if(Place(t)) Backtrack(t+1);
}
}
}
int main() {
//cin>>n;
Backtrack(1);
cout<<"Total="<<sum<<endl;
}


分支限界算法

装载问题分支限界算法的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
#define NUM 100
int n;//集装箱的数量
int c;//轮船的载重量
int w[NUM];////集装箱的重量数组
int MaxLoading()
{
queue<int> Q;
Q.push(-1);
int i = 0;
int Ew = 0;
int bestw = 0;
int r = 0;
for(int j=1; j<n; j++)
r += w[j];
while (true)
{
int wt = Ew+w[i];
if (wt<=c)
{
if (wt>bestw) bestw = wt;
if (i<n-1) Q.push(wt);
}
if (Ew+r>bestw && i<n-1) Q.push(Ew);
Ew = Q.front();
Q.pop();
if (Ew==-1)
{
if (Q.empty()) return bestw;
Q.push(-1);
Ew = Q.front();
Q.pop();
i++;
r -= w[i];
}
}
return bestw;
}
int main()
{
while(scanf("%d%d", &c, &n)!=EOF)
{
for(int i=0; i<n; i++)
scanf("%d",&w[i]);
int ans = MaxLoading();
if (ans) printf("%d\n", ans);
else printf("No answer!\n");
}
return 0;
}

请我吃辣条吧!