题目描述
n个人在做传递物品的游戏,编号为1-n。
游戏规则是这样的:开始时物品可以在任意一人手上,他可把物品传递给其他人中的任意一位;下一个人可以传递给未接过物品的任意一人。
即物品只能经过同一个人一次,而且每次传递过程都有一个代价;不同的人传给不同的人的代价值之间没有联系;
求当物品经过所有n个人后,整个过程的总代价是多少。
输入输出格式
输入格式:
第一行为n,表示共有n个人(16>=n>=2);
以下为n*n的矩阵,第i+1行、第j列表示物品从编号为i的人传递到编号为j的人所花费的代价,特别的有第i+1行、第i列为-1(因为物品不能自己传给自己),其他数据均为正整数(<=10000)。
输出格式:
一个数,为最小的代价总和。
输入输出样例
输入样例#1:
2
-1 9794
2724 –1输出样例#1:
2724
思路:状压 DP 入门题
每个人只能被传递一次,用一个 n 位二进制数来表示每个人是否被访问过,但这无法知道物品在谁手中,因此加一个状态,来表示物品在谁手中。
用 f[i][j] 表示在 i 状态时最后的一个是 j,初始状态为 f[1<<i][i]=0;表示一开始物品在i手中,所求状态为 min(f[(1<<n)-1][j]); 因此有转移方程:f[i][j]=min(f[i-(1<<j)][k]+cost[k][j],f[i][j])
k 表示从 k 点转移到了 j 位置,所以要求 j、k 都应该是集合 i 中的元素
源代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<ctime>
#include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 1001
#define MOD 10007
#define E 1e-6
#define LL long long
using namespace std;
LL f[1<<17][20],cost[20][20];
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>cost[i][j];
/*标识状态初始化*/
memset(f,127,sizeof(f));
for(int i=0;i<n;i++)
f[1<<i][i]=0;
int cnt=(1<<n)-1;
for(int i=1;i<=cnt;i++)
{
for(int j=0;j<n;j++)
{
if(i&(1<<j))
{
for(int k=0;k<n;k++)
{
if( j!=k && (i&(1<<k)) )//k在状态i中不存在
{
LL x=(i-(1<<j));
f[i][j]=min(f[x][k]+cost[k][j],f[i][j]);
}
}
}
}
}
LL minn=INF;
for(int i=0;i<n;i++)
minn=min(minn,f[cnt][i]);
cout<<minn<<endl;
return 0;
}