poj3311
因為這道題 點N 不超過10 可以 把狀態轉化 為 二進制數,0表示沒經過這個點,1表示經過這個點。
dp[i][j] 表示的是 在 i 狀態 下 到達j 的最短路徑
#include<cstdio>
#include<cstring>
using namespace std;
int mapp[11][11];
int dp[1<<13][13];
int n;
int main()
{
while(~scanf("%d",&n)&&n)
{
memset(mapp,0,sizeof(mapp));
memset(dp,-1,sizeof(dp));
for(int i=0;i<=n;i++)
{
for(int j=0;j<=n;j++)
{
scanf("%d",&mapp[i][j]);
}
}
for(int k=0;k<=n;k++)
{
for(int i=0;i<=n;i++)
{
for(int j=0;j<=n;j++)
{
if(mapp[i][j]>mapp[i][k]+mapp[k][j])
{
mapp[i][j]=mapp[i][k]+mapp[k][j];
}
}
}
}
dp[1][0]=0;
for(int i=1;i<(1<<(n+1));i++)
{
i=i|1;
for(int j=0;j<=n;j++)
{ // 可以 這個狀態可以 到達 j
if(dp[i][j]!=-1)
{
for(int k=0;k<=n;k++)
{
if(j!=k&&(dp[i|(1<<k)][k]==-1||(dp[i|(1<<k)][k]>dp[i][j]+mapp[j][k])))
{
// 這個狀態 到達 k 為 狀態 i 到達 j 的 最短路到達
dp[i|(1<<k)][k]=dp[i][j]+mapp[j][k];
}
}
}
}
}
printf("%d\n",dp[(1<<(n+1))-1][0]);
}
return 0;
}
hdu5418
題目跟上一題 略有不同,我是在之前的代碼上改的。
所以下標都減一。
#include<cstdio>
#include<cstring>
using namespace std;
int mapp[18][18];
int dp[1<<18][18];
int n,m;
int a,b,v;
int main()
{ int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(mapp,-1,sizeof(mapp));
memset(dp,-1,sizeof(dp));
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&v);
a--;
b--;
int te=mapp[a][b];
if(te==-1||te>v)
{
mapp[a][b]=v;
mapp[b][a]=v;
}
}
for(int k=0;k<n;k++)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(mapp[i][k]!=-1&&mapp[k][j]!=-1)
{
if(mapp[i][j]==-1||(mapp[i][j]>mapp[i][k]+mapp[k][j]))
{
mapp[i][j]=mapp[i][k]+mapp[k][j];
}
}
}
}
}
dp[1][0]=0;
for(int i=1;i<(1<<(n));i++)
{
i=i|1;
for(int j=0;j<n;j++)
{ // 可以 這個狀態可以 到達 j
if(dp[i][j]!=-1)
{
for(int k=0;k<n;k++)
{
if(j!=k&&(dp[i|(1<<k)][k]==-1||(dp[i|(1<<k)][k]>dp[i][j]+mapp[j][k])))
{
// 這個狀態 到達 k 為 狀態 i 到達 j 的 最短路到達
dp[i|(1<<k)][k]=dp[i][j]+mapp[j][k];
}
}
}
}
}
printf("%d\n",dp[(1<<(n))-1][0]);
}
return 0;
}