您的位置:首页 > 其它

HDU 3001【状态压缩DP】

2015-11-06 21:24 309 查看
题意:

给n个点m条无向边。

要求每个点最多走两次,要访问所有的点给出要求路线中边的权值总和最小。

思路:

三进制状态压缩DP,0代表走了0次,1,2类推。

第一次弄三进制状态压缩DP,感觉重点是对数据的预处理,利用数组分解各个位数,从而达到类似二进制的目的。

然后就是状态的表示,dp[s][i]表示状态s时到达i的最优值。

状态转移也一目了然,不废话。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
int pho[15][15];
int unit[12];
int dic[60000][11];
int dp[60000][11];
inline void init()
{
memset(dic,0,sizeof(dic));
unit[0]=1;
for(int i=1;i<=11;i++)
{
unit[i]=3*unit[i-1];
}
for(int i=0;i<=59049;i++)
{
int tmp=i;
for(int j=0;tmp;j++)
{
dic[i][j]=tmp%3;
tmp/=3;
}
}
}
int main()
{
int n,m;
init();
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
pho[i][j]=inf;
}
pho[i][i]=0;
}
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
pho[a][b]=pho[b][a]=min(pho[a][b],c);
}
int ed=1;
for(int i=1;i<=n;i++)
{
ed*=3;
}
ed--;
for(int s=0;s<=ed;s++)
{
for(int i=1;i<=n;i++)
{
dp[s][i]=inf;
}
}
bool ok;
int ans=inf;
for(int s=0;s<=ed;s++)
{
ok=1;
for(int i=1;i<=n;i++)
{
if(dic[s][i-1])
{
if(s==unit[i-1])
{
dp[s][i]=0;
}
else
{
for(int k=1;k<=n;k++)
{
if(i!=k&&(dic[s][k-1]))
{
dp[s][i]=min(dp[s][i],dp[s-unit[i-1]][k]+pho[k][i]);
}
}
}
}
else
{
ok=0;
}
}
if(ok)
{
for(int i=1;i<=n;i++)
{
ans=min(ans,dp[s][i]);
}
}
}
if(ans>=inf)
ans=-1;
printf("%d\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: