http://poj.org/problem?id=1080 http://acm.hdu.edu.cn/showproblem.php?pid=1080

#include <iostream>
#include <cstdio>
#include <map>
#include <cstring>

#define MAX(x,y,z) ((x)>(y)?((x)>(z)?(x):(z)):((y)>(z)?(y):(z)))

using namespace std;

char str1[105];
char str2[105];
int list[6][6] = {
//	  		{ \0,  A,  C,  G,  T,  -}
	/*\0*/	{  0,  0,  0,  0,  0,  0},
	/*A*/	{  0,  5, -1, -2, -1, -3},
	/*C*/	{  0, -1,  5, -3, -2, -4},
	/*G*/	{  0, -2, -3,  5, -2, -2},
	/*T*/	{  0, -1, -2, -2,  5, -1},
	/*-*/	{  0, -3, -4, -2, -1,  0},
};
map<char, int>m;

int dp[105][105];//dp[x][y]表示str1中1...x-1个字符和str2中第1...y-1之间匹配的最优解

int main(int argc, char const *argv[])
{
	int T, len1, len2;
	scanf("%d", &T);

	m['\0'] = 0;
	m['A'] = 1;
	m['C'] = 2;
	m['G'] = 3;
	m['T'] = 4;
	m['-'] = 5;

	while (T--) {
		memset(dp, 0, sizeof(dp));
		scanf("%d%s", &len1, str1 + 1);
		scanf("%d%s", &len2, str2 + 1);

		// printf("\t\t");
		// for (int y = 0; y < len2; y++) {
		// 	printf("%c\t", s2[y]);
		// }
		// printf("\n\t");

		// for (int y = 0; y <= len2; y++) {
		// 	printf("%d\t", dp[0][y]);

		// }
		// printf("\n");

		for (int x = 1; x <= len1 + 1; x++) {
			dp[x][0] = -1e9;
		}

		for (int y = 1; y <= len2 + 1; y++) {
			dp[0][y] = -1e9;
		}

		for (int x = 1; x <= len1 + 1; x++) {

			for (int y = 1; y <= len2 + 1; y++) {
				dp[x][y] = MAX(
				               dp[x - 1][y - 1] + list[m[str1[x - 1]]][m[str2[y - 1]]],
				               dp[x - 1][y] + list[m[str1[x - 1]]][m['-']],
				               dp[x][y - 1] + list[m['-']][m[str2[y - 1]]]
				           );

//取消注釋打印流程

/*				if (dp[x - 1][y - 1] + list[m[str1[x - 1]]][m[str2[y - 1]]]
				        >= dp[x - 1][y] + list[m[str1[x - 1]]][m['-']]) {
					if (dp[x - 1][y - 1] + list[m[str1[x - 1]]][m[str2[y - 1]]]
					        >=
					        dp[x][y - 1] + list[m['-']][m[str2[y - 1]]]) {
						printf("↖%d\t", dp[x][y]);
					} else {
						printf("←%d\t", dp[x][y]);
					}
				} else {
					if (dp[x - 1][y] + list[m[str1[x - 1]]][m['-']]
					        >=
					        dp[x][y - 1] + list[m['-']][m[str2[y - 1]]]) {
						printf("↑%d\t", dp[x][y]);
					} else {
						printf("←%d\t", dp[x][y]);

					}
				}
*/

			}

/*
			printf("\n");
*/

		}
		printf("%d\n", dp[len1 + 1][len2 + 1]);

		/**
		*
		*	in:
		*	
		*	2
		*	7 AGTGATG
		*	5 GTTAG
		*	7 AGCTATT
		*	9 AGCTTTAAA
		*	
		*	out:
		*	
		*	↖0		←-2		←-3		←-4		←-7		←-9
		*	↑-3		↖-2		↖-3		↖-4		↖1		←-1
		*	↑-5		↖2		←1		←0		↑-1		↖6
		*	↑-6		↑1		↖7		↖6		←3		↑5
		*	↑-8		↖-1		↑5		↖5		↖4		↖8
		*	↑-11	↑-4		↑2		↖4		↖10		←8
		*	↑-12	↑-5		↖1		↖7		↑9		↖8
		*	↑-14	↖-7		↑-1		↑5		↑7		↖14
		*	
		*	14
		*	
		*	↖0		←-3		←-5		←-9		←-10	←-11	←-12	←-15	←-18	←-21
		*	↑-3		↖5		←3		←-1		←-2		←-3		←-4		↖-7		↖-10	↖-13
		*	↑-5		↑3		↖10		←6		←5		←4		←3		←0		←-3		←-6
		*	↑-9		↑-1		↑6		↖15		←14		←13		←12		←9		←6		←3
		*	↑-10	↑-2		↑5		↑14		↖20		↖19		↖18		←15		←12		←9
		*	↑-13	↖-5		↑2		↑11		↑17		↖19		↖18		↖23		↖20		↖17
		*	↑-14	↑-6		↑1		↑10		↖16		↖22		↖24		↑22		↖22		↖19
		*	↑-15	↑-7		↑0		↑9		↖15		↖21		↖27		←24		↖21		↖21
		*	
		*	
		*	21
		*	
		*	
		*	
		*/

	}
	return 0;
}

后来发现是自己想得太多了,这个题的“状态”不一定非要理解成原先那样, 其实完全可以也像最大公共子列那样的, dp[x][y]表示str1的前x个字符和str2的前y个字符之间的匹配结果的最优解 这样也便于理解,便于思考

这样的话dp[x][y]就是最终答案,不过要注意边界的预处理 代码如下

#include <iostream>
#include <cstdio>
#include <map>
#include <cstring>

#define MAX(x,y,z) ((x)>(y)?((x)>(z)?(x):(z)):((y)>(z)?(y):(z)))

using namespace std;

char str1[105];
char str2[105];
int list[6][6] = {
//	  		{  A,  C,  G,  T,  -}
	/*A*/	{  5, -1, -2, -1, -3},
	/*C*/	{ -1,  5, -3, -2, -4},
	/*G*/	{ -2, -3,  5, -2, -2},
	/*T*/	{ -1, -2, -2,  5, -1},
	/*-*/	{ -3, -4, -2, -1,  0},
};

map<char, int>m;

int dp[105][105];//dp[x][y]表示str1中1...x个字符和str2中第1...y这两个子串之间的所有匹配方式的最大利益

int main(int argc, char const *argv[])
{
	int T, len1, len2;
	scanf("%d", &T);

	m['A'] = 0;
	m['C'] = 1;
	m['G'] = 2;
	m['T'] = 3;
	m['-'] = 4;

	while (T--) {
		memset(dp, 0, sizeof(dp));
		scanf("%d%s", &len1, str1 + 1);
		scanf("%d%s", &len2, str2 + 1);

		// printf("\t\t");
		// for (int y = 0; y < len2; y++) {
		// 	printf("%c\t", s2[y]);
		// }
		// printf("\n\t");

		// for (int y = 0; y <= len2; y++) {
		// 	printf("%d\t", dp[0][y]);

		// }
		// printf("\n");

		for (int x = 1; x <= len1; x++) {
			dp[x][0] = dp[x - 1][0] + list[m[str1[x]]][m['-']];
		}

		// printf("↖0\t");
		for (int y = 1; y <= len2; y++) {
			dp[0][y] = dp[0][y - 1] + list[m[str2[y]]][m['-']];
			// printf("←%d\t", dp[0][y]);
		}
		// printf("\n");

		for (int x = 1; x <= len1; x++) {

			// printf("↑%d\t", dp[x][0]);

			for (int y = 1; y <= len2; y++) {
				dp[x][y] = MAX(
				               dp[x - 1][y - 1] + list[m[str1[x]]][m[str2[y]]],
				               dp[x - 1][y] + list[m[str1[x]]][m['-']],
				               dp[x][y - 1] + list[m['-']][m[str2[y]]]
				           );

//取消所有额外注释可打印流程
				/*
								if (dp[x - 1][y - 1] + list[m[str1[x]]][m[str2[y]]]
								        >= dp[x - 1][y] + list[m[str1[x]]][m['-']]) {
									if (dp[x - 1][y - 1] + list[m[str1[x]]][m[str2[y]]]
									        >=
									        dp[x][y - 1] + list[m['-']][m[str2[y]]]) {
										printf("↖%d\t", dp[x][y]);
									} else {
										printf("←%d\t", dp[x][y]);
									}
								} else {
									if (dp[x - 1][y] + list[m[str1[x]]][m['-']]
									        >=
									        dp[x][y - 1] + list[m['-']][m[str2[y]]]) {
										printf("↑%d\t", dp[x][y]);
									} else {
										printf("←%d\t", dp[x][y]);

									}
								}
				*/

			}

			/*
						printf("\n");
			*/

		}
		printf("%d\n", dp[len1][len2]);

		/**
		*
		*	in:
		*
		*	2
		*	7 AGTGATG
		*	5 GTTAG
		*	7 AGCTATT
		*	9 AGCTTTAAA
		*
		*	out:
		*
		*	↖0		←-2		←-3		←-4		←-7		←-9
		*	↑-3		↖-2		↖-3		↖-4		↖1		←-1
		*	↑-5		↖2		←1		←0		↑-1		↖6
		*	↑-6		↑1		↖7		↖6		←3		↑5
		*	↑-8		↖-1		↑5		↖5		↖4		↖8
		*	↑-11	↑-4		↑2		↖4		↖10		←8
		*	↑-12	↑-5		↖1		↖7		↑9		↖8
		*	↑-14	↖-7		↑-1		↑5		↑7		↖14
		*
		*	14
		*
		*	↖0		←-3		←-5		←-9		←-10	←-11	←-12	←-15	←-18	←-21
		*	↑-3		↖5		←3		←-1		←-2		←-3		←-4		↖-7		↖-10	↖-13
		*	↑-5		↑3		↖10		←6		←5		←4		←3		←0		←-3		←-6
		*	↑-9		↑-1		↑6		↖15		←14		←13		←12		←9		←6		←3
		*	↑-10	↑-2		↑5		↑14		↖20		↖19		↖18		←15		←12		←9
		*	↑-13	↖-5		↑2		↑11		↑17		↖19		↖18		↖23		↖20		↖17
		*	↑-14	↑-6		↑1		↑10		↖16		↖22		↖24		↑22		↖22		↖19
		*	↑-15	↑-7		↑0		↑9		↖15		↖21		↖27		←24		↖21		↖21
		*
		*
		*	21
		*
		*
		*
		*/

	}
	return 0;
}