一.题目链接:
HDU-3001
二.题目大意:
n 个点,m 条双向边.
之后 m 行
每行三个整数 a,b,c 表示第 i 条边的起点,终点,权值.
要求每个点都走到且不超过两次.
求最小花费.
三.分析:
一道状压 DP 模板题
状压 DP 入门
详见代码.
四.代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-6
#define pi acos(-1.0)
#define ll long long int
using namespace std;
const int M = (int)6e4;
const int inf = 0x3f3f3f3f;
int three[10];///3 的 i 次方
int dp[M][10];///第 i 个状态以 j 为终点的最小距离
int cnt[M][10];///第 i 个状态 j 点走的次数
int path[10][10];///记录边
void init()
{
three[0] = 1;
for(int i = 1; i <= 10; ++i)
three[i] = three[i - 1] * 3;
for(int i = 0; i < three[10]; ++i)
{
int tmp = i;
for(int j = 0; j < 10; ++j)
{
cnt[i][j] = tmp % 3;
tmp /= 3;
}
}
}
int main()
{
init();
int n, m;
while(~scanf("%d %d", &n, &m))
{
memset(dp, inf, sizeof(dp));
memset(path, inf, sizeof(path));
int a, b, c;
while((m--) > 0)
{
scanf("%d %d %d", &a, &b, &c);
path[a - 1][b - 1] = path[b - 1][a - 1] = min(path[a - 1][b - 1], c);
}
for(int i = 0; i < n; ++i)
dp[three[i]][i] = 0;///只有自身的状态中以自身结束的距离为 0.
int ans = inf;
for(int i = 0; i < three[n]; ++i)
{
bool flag = 1;///记录第 i 个状态每个点是否都能走过
for(int j = 0; j < n; ++j)
{
if(!cnt[i][j])
flag = 0;
else
{
for(int k = 0; k < n; ++k)寻找 j 的后继点 k
{
if(path[j][k] != inf && cnt[i][k] < 2)///只有当前 i 状态走过 k 点的次数小于 2 时,才能走 k 点并更新状态
{
dp[i + three[k]][k] = min(dp[i + three[k]][k], dp[i][j] + path[j][k]);///更新状态
}
}
}
}
if(flag)
{
for(int j = 0; j < n; ++j)
ans = min(ans, dp[i][j]);
}
}
if(ans == inf)
printf("-1\n");
else
printf("%d\n", ans);
}
return 0;
}