hdu 3001(状态压缩dp)

来源:互联网 发布:淘宝全球购特点 编辑:程序博客网 时间:2024/06/15 20:25
#include <iostream>#include <cstdio>#include <cstring>#define Max1 10  #define Max2 59049 // 3^10#define INF 0x3f3f3f3fusing namespace std;/*由于每个点可经过两次 用三进制数表示状态  例10020(三进制)表示经过点2两次点1一次其余点都没经过*/int n, m, ans;int Pow[Max1 + 2], State[Max2 + 2][Max1 + 2];//Pow[n]意为3^n, State[n][m]意为状态n下经过m点的次数int dp[Max2 + 2][Max1 + 2], Map[Max1 + 2][Max1 + 2];//dp[n][m]意为状态为n且现位于m点时的费用, Map即为邻接矩阵存图inline int min(int a, int b) {return a < b ? a : b;}void Init() {int i;Pow[0] = 1;for(i = 1; i <= Max1; i++)Pow[i] = Pow[i - 1] * 3;for(i = 0; i < Pow[Max1]; i++) {int num = i;int cur = 1;while(num) {State[i][cur] = num % 3;num /= 3, cur++;}}//将十进制数i转化为三进制数,初始化State}bool Check(int x) {int i;bool flag = 1;for(i = 1; i <= n; i++)if(State[x][i] == 0) {flag = 0;break;}return flag;//检测状态x是否经过所有点}void Dp() {int i, j, k;for(i = 0; i < Pow[n]; i++) {//枚举状态ifor(j = 1; j <= n; j++) {//枚举当前所在点jif(dp[i][j] == INF)continue;//该情况不存在for(k = 1; k <= n; k++) {//枚举下一步到达的点kif((j == k) || (Map[j][k] == INF))continue;if(State[i][k] == 2)continue;//j和k同一点  不存在j到k的路线  i状态下已经经过两次k点dp[i + Pow[k - 1]][k] = min(dp[i + Pow[k - 1]][k], dp[i][j] + Map[j][k]);//从j点到k点  状态i转变为i + Pow[k - 1][k]//例 状态i为10020(三进制)j为2 k为1时满足上述条件 即状态变为10021(三进制)if(Check(i + Pow[k - 1]))ans = min(ans, dp[i + Pow[k - 1]][k]);}}}}int main() {int i, a, b, v;Init();while(~scanf("%d%d", &n, &m)) {ans = INF;memset(dp, INF, sizeof(dp));memset(Map, INF, sizeof(Map));for(i = 1; i <= n; i++)dp[Pow[i - 1]][i] = 0;//只经过点i的状态 且位于点i 初始化为0for(i = 1; i <= m; i++) {scanf("%d%d%d", &a, &b, &v);Map[a][b] = Map[b][a] = min(Map[a][b], v);}Dp();if(ans == INF)ans = -1;printf("%d\n", ans);}return 0;}

0 0
原创粉丝点击