求一条从一点出发来回的最长路。将问题转化为从某点出发的到达N点的两条不相交的路径。
定义dp[i][j]表示第一个点到达i点,第二个点到达j点所经过的最多顶点数,初始状态为dp[1][1] = 1表示从1,1点出发经过的顶点数为1.
动态方程:dp[i][j] = max( dp[i][k] + 1 ) 前提是 k,j 之间有边; 整个状态不去更新dp[i][i],因为如果更新了这个状态就可能使得最优解中包含了相同的点。
代码如下:
#include <cstring> #include <cstdio> #include <cstdlib> #include <map> #include <string> #include <cstring> #define INF 0x3fffffff #define MAXN 105 using namespace std; int N, M; bool G[MAXN][MAXN]; int dp[MAXN][MAXN]; map<string, int>mp; int DP() { int ret = 1; dp[1][1] = 1; for (int i = 1; i <= N; ++i) { for (int j = i+1; j <= N; ++j) { // 巧妙的绕过了对dp[i][i]的更新 int t = -INF; for (int k = 1; k < j; ++k) { if (G[k][j] && dp[i][k] > 0 && dp[i][k] > t) { t = dp[i][k]; } } if (t != -INF) dp[j][i] = dp[i][j] = t + 1; } } for (int i = 1; i <= N; ++i) { if (G[i][N] && dp[i][N] > ret) ret = dp[i][N]; } return ret; } int main() { char str[100], a[100]; while (scanf("%d %d", &N, &M) == 2) { memset(G, 0, sizeof (G)); memset(dp, 0, sizeof (dp)); for (int i = 1; i <= N; ++i) { scanf("%s", str); mp[str] = i; } for (int i = 1; i <= M; ++i) { scanf("%s %s", str, a); G[ mp[str] ][ mp[a] ] = true; G[ mp[a] ][ mp[str] ] = true; } printf("%d\n", DP()); } return 0; }