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;

}

你可能感兴趣的:(AIR)