POJ3311 FLOYD+DP 旅行商类问题[模板]

来源:互联网 发布:纸猫 澳大利亚 知乎 编辑:程序博客网 时间:2024/06/16 07:54

思路:

先用floyd处理一次这个很容易想到。

查了一下网上都是用旅行商问题。

第一次做这种旅行商DP问题。下面是参考别人的代码。

据说用传统枚举暴力也可以的。

因为N=10;

#include<stdio.h>
int n;
const int N=12;
int dp[1<<11][N];
int mat[N][N];
int pre[N];
const int inf=99999999;
int min(int a,int b)
{
if(a<b)
return a;
return b;
}
void floyd()
{
for(int k=0;k<=n;k++)
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
if(mat[i][j]>mat[i][k]+mat[k][j])
{
mat[i][j]=mat[i][k]+mat[k][j];
pre[j]=i;
}
}
int main()
{
while(scanf("%d",&n),n!=0)
{
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
scanf("%d",&mat[i][j]);
floyd();
for(int s=0;s<=(1<<n)-1;s++)//枚举所有状态
for(int i=1;i<=n;i++)//枚举每个点
{
if(s&(1<<(i-1)))//当访问过这个点
{
if(s==(1<<i-1))//边界条件:当且仅当访问过这个店。即直接从源点到该店,所以dp[s][i]=mat[0][i];
dp[s][i]=mat[0][i];
else//不只访问过这个点
{
dp[s][i]=inf;//这个初始化不能丢。
for(int j=1;j<=n;j++)//再枚举一遍,找出除了i点外的其它全部点。
{
if(s&(1<<(j-1))&&j!=i)
dp[s][i]=min(dp[s^(1<<(i-1))][j]+mat[j][i],dp[s][i]);//关键部分dp转移方程。^是异或运算。这里我觉得其实有点类似floyd的找中间节点的算法思想。
}
}
}
}
int ans=dp[(1<<n)-1][1]+mat[1][0];
for(int i=2;i<=n;i++)
if(dp[(1<<n)-1][i]+mat[i][0]<ans)
ans=dp[(1<<n)-1][i]+mat[i][0];
printf("%d\n",ans);
}


return 0;
}

代码分析都直接写在注释里了。

其实现在对于这种算法还不是很掌握。

日后再回顾吧。

原创粉丝点击