状压DP入门 传球游戏之最小总代价

本人水平有限,题解不到为处,请多多谅解

本蒟蒻谢谢大家观看

题目:

Problem B: 传球游戏之最小总代价

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 89  Solved: 43
[Submit][Status][Web Board]

Description

n个人在做传递物品的游戏,编号为1-n。游戏规则是这样的:开始时物品可以在任意一人手上,他可把物品传递给
其他人中的任意一位;下一个人可以传递给未接过物品的任意一人。即物品只能经过同一个人一次,而且每次传递
过程都有一个代价;不同的人传给不同的人的代价值之间没有联系;求当物品经过所有n个人后,整个过程的总代
价是多少。 

Input

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

Output

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

Sample Input

2
-1 9794
2724 –1

Sample Output

2724

HINT

   f[i][j]表示在当前状态下的以j结尾需要的最小代价总和;

  dis[i][j]表示以i开始,以j结尾的距离;

  读入时可以手动把n=-1给特判掉;

  初始化:for(i=1 to down n)  f[1<<i-1][i]=0;  //表示可以以任意一个数开始,到自身的代价为0。

  转移:f[i][j]=min(f[i][j],f[i^1<<j-1][k]+dis[k][j]);  //表示(上一个状态的最小代价和 + 当前的距离  与 当前状态的最小代价总和)取min;

  结尾:for(i=1 to down (1<<n)-1) ans=min(ans,f[(1<<n)-1][i])  //表示所有状态枚举完时,可以以任意一个数结尾需要的最小代价总和;取min即可

 code:
#include<bits/stdc++.h>
using namespace std;
int n;
int dis[21][21];
int ans;
int f[1<<20][21];
inline int read(){
     int x=0,f=1;
     char ch=getchar();
     while(ch<'0'||ch>'9'){
         if(ch=='-')
             f=-1;
         ch=getchar();
     }
     while(ch>='0'&&ch<='9'){
         x=(x<<1)+(x<<3)+(ch^48);
         ch=getchar();
     }
     return x*f;
}

inline void write(int x){
     char F[200];
     int tmp=x>0?x:-x ;
     if(x<0)putchar('-') ;
     int cnt=0 ;
        while(tmp>0)
        {
            F[cnt++]=tmp%10+'0';
            tmp/=10;
        }
        while(cnt>0)putchar(F[--cnt]) ;
}

int main()
{
        n=read();
    if(n!=-1)
    {
        ans=INT_MAX;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                dis[i][j]=read();
            }
        }
        memset(f,0x3f,sizeof(f));
        for(int i=1;i<=n;i++)
        f[1<<i-1][i]=0;
        for(int i=1;i<=(1<<n)-1;i++)
        {
            for(int j=1;j<=n;j++)
            {    
                
                if(i&1<<j-1)
                {
                    for(int k=1;k<=n;k++)
                    {
                        if(i&1<<k-1&&j!=k)
                        {
        f[i][j]=min(f[i][j],f[i^1<<j-1][k]+dis[k][j]);
                        }
                    }
                }
            }
        }
        for(int i=1;i<=n;i++)
            ans=min(ans,f[(1<<n)-1][i]);
        write(ans);
    }
        cout<<endl;
    return 0;    
} 
 
原文地址:https://www.cnblogs.com/nlyzl/p/11307139.html