您的位置:首页 > 大数据 > 人工智能

[caioj 1425][状态压缩]游戏---状态压缩dp

2017-10-25 09:50 471 查看

题目描述

题意

n个人在做传递物品的游戏,编号为1-n。

游戏规则是这样的:开始时物品可以在任意一人手上,他可把物品传递给其他人中的任意一位;下一个人可以传递给未接过物品的任意一人。

即物品只能经过同一个人一次,而且每次传递过程都有一个代价;不同的人传给不同的人的代价值之间没有联系;

求当物品经过所有n个人后,整个过程的总代价是多少。

输入

  第一行为n,表示共有n个人(16>=n>=2);

以下为n*n的矩阵,第i+1行、第j列表示物品从编号为i的人传递到编号为j的人所花费的代价,特别的有第i+1行、第i列为-1(因为物品不能自己传给自己),其他数据均为正整数(<=10000)。

(对于50%的数据,n<=11)。

输出

输出共一个数,为最小的代价总和。

样例输入

2

-1 9794

2724 –1

样例输出

2724

分析

如题名如范围,标准状压dp.

将n个人是否接过物品的状态用二进制压成0–2^n-1之间的数,其中,1<< i-1( 即 2^(i-1) )表示第i个人接过物品

令f[s][i]表示物品在s状态下传到了第i个人的手中,j表示某个未接过物品的人

则:f[s|(1< j-1)][j]=min( f[s][i]+dis[i][j] )

PS:初始化: f[1<< i-1][i]=0; 其余为inf

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#define open(s) freopen(s".in","r",stdin); freopen(s".out","w",stdout);
#define close fclose(stdin); fclose(stdout);
using namespace std;

int n;
int ans;
int inf;
int f[1<<16][17];
int dis[17][17];

inline int read()
{
int k=1;
int sum=0;
char c=getchar();
for(;'0'>
4000
;c || c>'9' ;c=getchar())
if(c=='-') k=-1;
for(;'0'<=c && c<='9';c=getchar())
sum=sum*10+c-'0';
return sum*k;
}

inline void write(int x)
{
if(x<0) { putchar('-'); x*=-1; }
if(x>9) write(x/10);
putchar(x%10+'0');
}

inline int min_(int x,int y) { return x<y?x:y; }

int main()
{
open("1425");

int n=read(),m;
m=(1<<n)-1;
memset(f,0x3f,sizeof(f));
inf=f[0][0];
for(int i=1;i<=n;++i)
{
f[1<<i-1][i]=0;
for(int j=1;j<=n;++j)
dis[i][j]=read();
}
ans=inf;
for(int s=1,v;s<m;++s)
for(int i=1;i<=n;++i)
if((s&(1<<i-1)) && f[s][i]!=inf)//增加限制条件可以剪枝(i必定在s中)
for(int j=1;j<=n;++j)
if(i!=j && !(s&(1<<j-1)))
{
v=s|(1<<j-1);
f[v][j]=min_(f[v][j],f[s][i]+dis[i][j]);
if(v==m) ans=min_(ans,f[v][j]);
}
write(ans);
close;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: