OJ練習
1. Multiplication Puzzle:http://poj.org/problem?id=1651
2. 【該題可以轉化爲矩陣連乘問題】
3. Common Subsequence:http://poj.org/problem?id=1458
4. 【該題只需要輸出最長公共子序列的長度】
3*. Human Gene Functions:Human Gene Functions:http://poj.org/problem?id=1080【LCS變形】
4*. Compromise:http://poj.org/problem?id=2250【LCS問題】
5*. AGTC:http://poj.org/problem?id=3356【LCS問題】
6*.完美序列:http://acm.zcmu.edu.cn/JudgeOnline/problem.php?id=1539
實驗內容
1. 最長公共子序列問題(LCS)。在使用動態規劃算法來求解最長公共子序列時,二維數組c[i][j]用於記錄序列Xi和Yj的最長公共子序列的長度,對於序列X = {A, C, B, C, D, A, B, D}和Y = {A, B, D, C, A, B, A},繪製對應的c[i][j]。
所繪製的c[i][j]數組:
A C B C D A B D
0 0 0 0 0 0 0 0 0
A 0 1 1 1 1 1 1 1 1
B 0 1 1 2 2 2 2 2 2
D 0 1 1 2 2 3 3 3 3
C 0 1 2 3 3 3 3 3 3
A 0 1 2 2 3 3 4 4 4
B 0 1 2 3 3 3 4 5 5
A 0 1 2 3 3 3 4 5 5
- 最長公共子序列問題(LCS)。分別使用備忘錄法和動態規劃算法求解最長公共子序列的長度。【輸入:兩個字符序列;輸出:兩個字符序列的最長公共子序列的長度。例如:輸入序列A = “ABCBDAB”,序列B = “BDCABA”;輸出4】
備忘錄法源代碼:
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#define maxn 105
#define maxm 10005
#define INF 0x3f3f3f3f
using namespace std;
char a[maxn],b[maxn];
int dp[maxn][maxn],c[maxn][maxn];
int n,m;
int lcs1(int i, int j)
{
if(dp[i][j]) return dp[i][j];
if(!i || !j) return 0;
else if(a[i-1] == b[j-1])
dp[i][j] = lcs1(i-1,j-1)+1;
else
dp[i][j] = max(lcs1(i-1,j), lcs1(i,j-1));
return dp[i][j];
}
int main()
{
while(cin >> a >> b){
memset(dp,0,sizeof(dp));
n = strlen(a);
m = strlen(b);
lcs1(n,m);
cout << dp[n][m] << endl;
}
}
/*
ABCBDAB
BDCABA
*/
動態規劃算法源代碼:
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#define maxn 105
#define maxm 10005
#define INF 0x3f3f3f3f
using namespace std;
char a[maxn],b[maxn];
int dp[maxn][maxn],c[maxn][maxn];
int n,m;
void lcs1(int n, int m)
{
for(int i=1; i<=n; i++){
for(int j=1;j<=m; j++){
if(a[i-1]==b[j-1]){
dp[i][j] = dp[i-1][j-1] + 1;
c[i][j] = 1;
}
else if(dp[i-1][j] >= dp[i][j-1]){
dp[i][j] = dp[i-1][j];
c[i][j] = 2;
}
else{
dp[i][j] = dp[i][j-1];
c[i][j] = 3;
}
}
}
}
void lcs2(int i, int j)
{
if(!i || !j) return ;
if(c[i][j] == 1){
lcs2(i-1,j-1);
printf("%c",a[i-1]);
}
else if(c[i][j]==2){
lcs2(i-1,j);
}
else{
lcs2(i,j-1);
}
}
int main()
{
while(cin >> a >> b){
memset(dp,0,sizeof(dp));
memset(c,0,sizeof(c));
n = strlen(a);
m = strlen(b);
lcs1(n,m);
cout << endl;
cout << dp[n][m] << endl;
}
}
/*
ABCBDAB
BDCABA
*/
- 最長公共子序列問題(LCS)。在練習2代碼的基礎上,使用動態規劃算法構造一條最長公共子序列。【輸入:兩個字符序列;輸出:兩個字符序列的一條最長公共子序列。例如:輸入序列A = “ABCBDAB”,序列B = “BDCABA”;輸出”BCAB”(或其他任意一條長度爲4的公共子序列)】
源代碼:
#include<queue>
#include<iostream>
#define maxn 105
#define maxm 10005
#define INF 0x3f3f3f3f
using namespace std;
char a[maxn],b[maxn];
int dp[maxn][maxn],c[maxn][maxn];
int n,m;
void lcs1(int n, int m)
{
for(int i=1; i<=n; i++){
for(int j=1;j<=m; j++){
if(a[i-1]==b[j-1]){
dp[i][j] = dp[i-1][j-1] + 1;
c[i][j] = 1;
}
else if(dp[i-1][j] >= dp[i][j-1]){
dp[i][j] = dp[i-1][j];
c[i][j] = 2;
}
else{
dp[i][j] = dp[i][j-1];
c[i][j] = 3;
}
}
}
}
void lcs2(int i, int j)
{
if(!i || !j) return ;
if(c[i][j] == 1){
lcs2(i-1,j-1);
printf("%c",a[i-1]);
}
else if(c[i][j]==2){
lcs2(i-1,j);
}
else{
lcs2(i,j-1);
}
}
int main()
{
while(cin >> a >> b){
memset(dp,0,sizeof(dp));
memset(c,0,sizeof(c));
n = strlen(a);
m = strlen(b);
lcs1(n,m);
lcs2(n,m);
cout << endl;
cout << dp[n][m] << endl;
}
}
/*
ABCBDAB
BDCABA
*/
- 求如圖所示一個上三角矩陣中每一條斜線中的最大元素(L)和最小元素(S)。
輸入:
1 3 5 7 11 20
6 8 2 3 13
7 4 8 9
18 3 10
12 6
15
輸出:
L1 = 18, S1 = 1
L2 = 8, S2 = 3
L3 = 10, S3 = 2
L4 = 9, S4 = 3
L5 = 13, S5 = 11
L6 = 20, S6 = 20
源代碼:
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#include<bits/stdc++.h>
#define maxn 105
#define maxm 10005
#define INF 0x3f3f3f3f
using namespace std;
int a[maxn][maxn];
int n,m;
int Max = -INF, Min = INF;
int main()
{
n = 6;
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
cin >> a[i][j];
}
}
for(int r=1; r<=n; r++){
int Max = -INF, Min = INF;
for(int i=1; i<=n-r+1; i++){
int j = i + r - 1;
Max = max(Max,a[i][j]);
Min = min(Min,a[i][j]);
}
cout << "L1 = " << Max << ", " << "S1 = " << Min << endl;
}
return 0;
}
/*
1 3 5 7 11 20
0 6 8 2 3 13
0 0 7 4 8 9
0 0 0 18 3 10
0 0 0 0 12 6
0 0 0 0 0 15
*/
5. 矩陣連乘問題。使用動態規劃算法求解矩陣連乘問題。【輸入:一個存儲矩陣維數的一維數組;輸出:矩陣連乘最優計算次序。】
例如:
輸入:
一維數組{30, 35, 15, 5, 10, 20, 25}
輸出:
A[2:2] * A[3:3]
A[1:1] * A[2:3]
A[4:4] * A[5:5]
A[4:5] * A[6:6]
A[1:3] * A[4:6]
源代碼:
/*
#include<iostream>
using namespace std;
#define N 7
void MatrixChainOrder(int *p,int (*m)[N],int (*s)[N],int length)
{
int n=length-1;
int l,i,j,k,q=0;
for(i=1;i<length;i++)
{
m[i][i]=0;
}
for(l=2;l<=n;l++)
{
for(i=1;i<=n-l+1;i++)
{
j=i+l-1;
m[i][j]=0x7fffffff;
for(k=i;k<=j-1;k++)
{
q=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
if(q<m[i][j])
{
m[i][j]=q;
s[i][j]=k;
}
}
}
}
cout << m[1][N-1] << endl;
}
void Print(int(*s)[N],int i,int j)
{
if(i==j)
{
cout<<"A"<<i;
}
else
{
cout<<"(";
Print(s,i,s[i][j]);
Print(s,s[i][j]+1,j);
cout<<")";
}
}
int main()
{
int p[N]={20,35,15,5,10,20,25};
int m[N][N],s[N][N];
MatrixChainOrder(p,m,s,N);
Print(s,1,N-1);
return 0;
}
*/
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#include<bits/stdc++.h>
#define maxn 105
#define maxm 10005
#define INF 0x3f3f3f3f
using namespace std;
int a[maxn][maxn];
int n,m;
int Max = -INF, Min = INF;
void matrixChain(int *p, int **dp, int **s,int n)
{
for(int i=1; i<=n; i++) dp[i][i] = 0;
for(int r=2; r<=n; r++){
for(int i=1; i<=n-r+1; i++){
int j = i + r - 1;
dp[i][j] = dp[i+1][j] + p[i-1]*p[i]*p[j];
s[i][j] = i;
for(int k=i+1; k<j; k++){
int t = dp[i][k] + dp[k+1][j] + p[i-1]*p[k]*p[j];
if(t < dp[i][j]){
dp[i][j] = t;
s[i][j] = k;
}
}
}
}
cout << dp[1][n-1] << endl;
}
void dfs(int **s, int i, int j)
{
if(i==j) return ;
dfs(s,i,s[i][j]);
dfs(s,s[i][j]+1,j);
cout<<"A["<<i<<":"<<s[i][j]<<"]";
cout<<" * A"<<"["<<(s[i][j]+1)<<":"<<j<<"]"<<endl;
}
int main()
{
int p[7]={30,35,15,5,10,20,25};
int **s = new int *[7];
int **dp = new int *[7];
for (int i=0 ; i<7 ; ++i)
{
s[i]= new int[7];
dp[i] = new int[7];
}
matrixChain(p,dp,s,6);
cout<<endl;
dfs(s,1,6);
return 0;
}