状压DP入门 传球游戏之最小总代价
本人水平有限,题解不到为处,请多多谅解
本蒟蒻谢谢大家观看
题目:
Problem B: 传球游戏之最小总代价
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 89 Solved: 43
[Submit][Status][Web Board]
Description
n个人在做传递物品的游戏,编号为1-n。游戏规则是这样的:开始时物品可以在任意一人手上,他可把物品传递给
其他人中的任意一位;下一个人可以传递给未接过物品的任意一人。即物品只能经过同一个人一次,而且每次传递
过程都有一个代价;不同的人传给不同的人的代价值之间没有联系;求当物品经过所有n个人后,整个过程的总代
价是多少。
其他人中的任意一位;下一个人可以传递给未接过物品的任意一人。即物品只能经过同一个人一次,而且每次传递
过程都有一个代价;不同的人传给不同的人的代价值之间没有联系;求当物品经过所有n个人后,整个过程的总代
价是多少。
Input
第一行为n,表示共有n个人(16>=n>=2);
以下为n*n的矩阵,第i+1行、第j列表示物品从编号为i的人传递到编号为j的人所花费的代价,
特别的有第i+1行、第i列为-1(因为物品不能自己传给自己),其他数据均为正整数(<=10000)。
以下为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; }