HDU-Travel By Airline DP

求一条从一点出发来回的最长路。将问题转化为从某点出发的到达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;
}
posted @ 2012-08-22 10:57  沐阳  阅读(216)  评论(0编辑  收藏  举报