旅行商问题 TSP问题 状压dp入门 + floyd poj 3311 hdu 5418

旅行商问题 & TSP问题:有n个城市,从起点 0 开始游历每一个城市,只访问每个城市一次,最后回到起点,所需要的最短路径是多少?
这个属于NP完全问题。最直接的方法就是枚举法,解空间为n个元素的所有排列组合,为 (n1)! 。n稍微一大就无法在有限的时间内做出。还有一些模拟退火算法什么的,这个不太了解,有空再去了解下。
在acm中,对于此问题,n一般都不大,可以运用floyd + 状压dp来做。
状压dp:
对于集合的dp 被称为状态压缩dp。对于一个集合来说我们可以把每一个元素是否选取对应到一个二进制数位里,从而将状态压缩成一个整数。
TSP问题解法:
考虑使用dp来求解。
s表示已经经过的城市的集合,v表示现在正处在的城市。定义dp[s][v]为从v出发访问所有剩余的城市,再返回起点所需要的最短的路径。mp[i][j] 表示 i 到 j 的最短路。
V为所有顶点的集合。初始化dp[V][0] = 0
状态转移方程: dp[s][v]=min(dp[s| {u} ][u]+mp[u][v]) (u不属于s)
集合的表示:
可以运用上面说的状压dp的方法来做。
比如 5 个城市,表示成5位二进制数, 对于每一位来说(也就是每一个城市来说)0表示没有访问过,1表示已经访问过。 00000就表示都没有访问过。
求出mp[i][j] 即任意两点的最短路: 直接 floyd就好了。
poj 3311 记忆化搜索。。记忆化搜索好久没写过了,有点手生。。

#include 
#include 
#include 
#include 
using namespace std;
#define M 19
#define INF 0x3f3f3f3f
int n;
int mp[M][M];
int dp[1<<11][M];
void floyd()
{
    for(int k = 0;k < n;k++)
    {
        for(int i = 0;i < n;i++)
        {
            for(int j = 0;j < n;j++)
                mp[i][j] = min(mp[i][j],mp[i][k]+mp[k][j]);
        }
    }
}
int slove(int s,int v) //记忆化搜索
{
    if(dp[s][v] >= 0) return dp[s][v]; //已经有结果
    if(s == (1<1 && v == 0) return dp[s][v] = 0; //访问完所有城市
    int ret = INF;
    for(int u = 0;u < n;u++)//从u到v
    {
        if(!((s >> u) & 1)) //判断是否访问过,如果u这一位是0,即没有访问过
        ret = min(ret,slove(s|(1<//状态转移
    }
    return dp[s][v] = ret; //记录结果
}
int main()
{
    while(scanf("%d",&n) == 1 && n)
    {
        n++;
        for(int i = 0;i < n;i++) fill(mp[i],mp[i]+n,INF);
        for(int i = 0;i < n;i++)
        {
            for(int j = 0;j < n;j++)
                scanf("%d",&mp[i][j]);
        }
        floyd();
        memset(dp,-1,sizeof(dp));
        printf("%d\n",slove(0,0));
    }
    return 0;
}

hdu 5418 递推式:

#include 
#include 
#include 
#include 
using namespace std;
#define M 20
#define INF 0x3f3f3f3f
int n,m;
int mp[M][M];
int dp[1<void floyd()
{
    for(int k = 0;k < n;k++)
        for(int i = 0;i < n;i++)
            for(int j = 0;j < n;j++)
                mp[i][j] = min(mp[i][j],mp[i][k]+mp[k][j]);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&n,&m);
        for(int i = 0;i < M;i++) fill(mp[i],mp[i]+n,INF);
        for(int i = 0;i < m;i++)
        {
            int a,b,c;
            scanf("%d %d %d",&a,&b,&c);
            a--;b--;
            mp[a][b] = min(mp[a][b],c);
            mp[b][a] = mp[a][b];
        }
        for(int i = 0;i < n;i++)mp[i][i] = 0;
        floyd();
        int ans = INF;
        for(int j = 0;j < (1<1<1][0] = 0;
        for(int s = (1<2;s >= 0;s--)
        {
            for(int v = 0;v < n;v++)
            {
                for(int u = 0;u < n;u++)
                    if(!(s >> u & 1))
                    dp[s][v] = min(dp[s][v],dp[s|(1<printf("%d\n",dp[0][0]);
    }
    return 0;
}

你可能感兴趣的:(动态规划dp,挑战程序设计竞赛~,图论_最短路)