标签:
这个游戏在一个有10*10个格子的棋盘上进行,初始时棋子位于左上角,终点为右下角,棋盘上每个格子内有一个0到9的数字,每次棋子可以往右方或下方的相邻格子移动,求一条经过数字之和最小且经过0到9的所有数字的合法路径,输出其长度。(经过的数字包括左上角和右下角)
输入包含10行,每行10个数字,以空格隔开,表示棋盘格子上的权值。数据保证存在合法路径。
输出所求路径的权值和。
0 1 2 3 4 5 6 7 8 9
1 1 1 1 1 1 1 1 1 0
2 1 1 1 1 1 1 1 1 0
3 1 1 1 1 1 1 1 1 0
4 1 1 1 1 1 1 1 1 0
5 1 1 1 1 1 1 1 1 0
6 1 1 1 1 1 1 1 1 0
7 1 1 1 1 1 1 1 1 0
8 1 1 1 1 1 1 1 1 0
9 1 1 1 1 1 1 1 1 5
50
样例解释
先一直向右走到第一行末尾,再竖直向下走位最优路径。
正解:状压DP
解题报告:
最近没事做,刷点状压DP水题。
f[i][j][s]记录到达(i,j)时状态为s的最优答案,显然可以吧0到9是否走过压成二进制。复杂度正确。
转移的时候注意一下状态这一维度要在最内层,开始样例都没过,才发现状态必须在最里层。。。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 #ifdef WIN32 14 #define OT "%I64d" 15 #else 16 #define OT "%lld" 17 #endif 18 using namespace std; 19 typedef long long LL; 20 const int MAXN = 12; 21 const int MAXS = (1<<12); 22 int n; 23 int a[MAXN][MAXN]; 24 int f[MAXN][MAXN][MAXS]; 25 26 inline int getint() 27 { 28 int w=0,q=0; 29 char c=getchar(); 30 while((c<‘0‘ || c>‘9‘) && c!=‘-‘) c=getchar(); 31 if (c==‘-‘) q=1, c=getchar(); 32 while (c>=‘0‘ && c<=‘9‘) w=w*10+c-‘0‘, c=getchar(); 33 return q ? -w : w; 34 } 35 36 inline void solve(){ 37 n=10; memset(f,127/3,sizeof(f)); 38 for(int i=1;i<=n;i++) 39 for(int j=1;j<=n;j++) 40 a[i][j]=getint(); 41 int end=(1<<n)-1; 42 f[1][1][1<<a[1][1]]=a[1][1]; 43 //不能置为0!!!!!!只能从1出发 44 45 //for(int i=1;i<=n;i++) 46 // for(int j=1;j<=n;j++) 47 // f[i][j][0]=0; 48 49 for(int j=1;j<=n;j++) 50 for(int k=1;k<=n;k++) { 51 if(j==1 && k==1) continue; 52 for(int i=1;i<=end;i++) { 53 if((1<<a[j][k] | i )!=i) continue; 54 int lin=(1<<30); 55 lin=min(f[j-1][k][i],f[j][k-1][i]); 56 lin=min(lin,min(f[j-1][k][i-(1<<a[j][k])],f[j][k-1][i-(1<<a[j][k])])); 57 f[j][k][i]=lin+a[j][k]; 58 } 59 } 60 printf("%d",f[n][n][end]); 61 } 62 63 int main() 64 { 65 solve(); 66 return 0; 67 }
标签:
原文地址:http://www.cnblogs.com/ljh2000-jump/p/5655345.html