您的位置:首页 > 其它

三进制状压 HDOJ 3001 Travelling

2015-11-22 17:37 281 查看
题目传送门

题意:从某个点出发,所有点都走过且最多走两次,问最小花费

分析:数据量这么小应该是状压题,旅行商TSP的变形。dp[st][i]表示状态st,在i点时的最小花费,用三进制状压。以后任意进制状压都会了。

#include <bits/stdc++.h>
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 11;
int dp[60000][10];
int bit
;
int d

;
int p
;
int n, m;

void init(void)	{		//三进制0 1 2
bit[0] = 1;
for (int i=1; i<N; ++i)	{
bit[i] = bit[i-1] * 3;	//bit[i] 相当于在二进制下的 1 << i
}
}

void get_status(int st)	{
int i = 0;
memset (p, 0, sizeof (p));
while (st)	{
p[i++] = st % 3;
st /= 3;
}
}

int sum(void)	{
int ret = 0;
for (int i=0; i<n; ++i)	{
ret += p[i] * bit[i];
}
return ret;
}

int main(void)	{
init ();
while (scanf ("%d%d", &n, &m) == 2)	{
memset (d, INF, sizeof (d));
for (int u, v, w, i=0; i<m; ++i)	{
scanf ("%d%d%d", &u, &v, &w);
u--;	v--;
d[u][v] = d[v][u] = min (d[v][u], w);
}
int ans = INF;
memset (dp, INF, sizeof (dp));
for (int i=0; i<n; ++i)	{		//初始化,三进制下10000的状态,现在在第i个点时花费0
dp[bit[i]][i] = 0;
}
for (int i=0; i<bit
; ++i)	{
bool flag = true;
get_status (i);
for (int j=0; j<n; ++j)	{
if (p[j] == 0)	flag = false;
if (dp[i][j] == INF)	continue;
for (int k=0; k<n; ++k)	{
if (p[k] == 2 || d[j][k] == INF || k == j)	continue;
p[k]++;
int v = sum ();
dp[v][k] = min (dp[v][k], dp[i][j] + d[j][k]);
p[k]--;
}
}
if (flag)	{		//每个点至少都走过一次的状态
for (int j=0; j<n; ++j)	{
ans = min (ans, dp[i][j]);
}
}
}
if (ans == INF)	ans = -1;
printf ("%d\n", ans);
}

return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: