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

来源:互联网 发布:mac电池健康度怎么看 编辑:程序博客网 时间:2024/06/08 11:35

题目描述

题意

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'>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;}
原创粉丝点击