hdu3001(三进制状态压缩dp)

链接:点击打开链接

题意:n个城市,m条路,每个城市最多经过两次,遍历所有城市最小的费用是多少

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
int three[15]={1,3,9,27,81,243,729,2187,6561,19683,59049};
int d[20][20],dp[60005][15],vis[60005][15];
int main(){
    char str[1005];
    int V,m,i,j,k,s,u,v,w,ans,tmp,sign;
    for(i=0;i<=three[10];i++){
        tmp=i;
        for(j=0;j<10;j++){
            vis[i][j]=tmp%3;
            tmp/=3;
        }
    }
    while(scanf("%d%d",&V,&m)!=EOF&&V){
        memset(d,INF,sizeof(d));
        memset(dp,INF,sizeof(dp));
        for(i=0;i<V;i++)
        dp[three[i]][i]=0;
        for(i=0;i<m;i++){
            scanf("%d%d%d",&u,&v,&w);
            d[u-1][v-1]=min(d[u-1][v-1],w);
            d[v-1][u-1]=d[u-1][v-1];
        }                                       //有重边
        ans=INF;
        for(s=0;s<three[V];s++){                //因为每个点最多经过两回,因此
            sign=0;                             //就是TSP变为三进制,剩下跟二进
            for(u=0;u<V;u++){                   //制时一样
                if(vis[s][u]==0)
                sign=1;
                if(dp[s][u]!=INF)
                for(v=0;v<V;v++)
                if(vis[s][v]!=2&&d[u][v]!=INF)
                dp[s+three[v]][v]=min(dp[s+three[v]][v],dp[s][u]+d[u][v]);
            }
            if(sign==0)                         //最后不好判断是否有没走过的点
            for(i=0;i<V;i++)                    //因此在中间判断
            ans=min(ans,dp[s][i]);
        }
        if(ans>=INF)
        puts("-1");
        else
        printf("%d\n",ans);
    }
    return 0;
}


 

你可能感兴趣的:(源码,动态规划,ACM,poj)