CODEVS1358【DFS/状压DP】

题目链接【http://codevs.cn/problem/1358/】

题意:这个游戏在一个有10*10个格子的棋盘上进行,初始时棋子位于左上角,终点为右下角,棋盘上每个格子内有一个0到9的数字,每次棋子可以往右方或下方的相邻格子移动,求一条经过数字之和最小且经过0到9的所有数字的合法路径,输出其长度。(经过的数字包括左上角和右下角)。

思路一:深搜(DFS),因为他只可以向左走或又走,那么每次有两个方向,走到终点的时候,最多走了20步,所以深度最深为20,可解。

 

#include<cstdio>
#include<cstring>
#include<algorithm>
const int inf = 1e9 + 10;
using namespace std;
int a[15][15];
int ans = inf;
void DFS(int x, int y, int k, int sum)
{
    if(x < 1 || x > 10 || y < 1 || y > 10) return ;
    k |=(1 << a[x][y]);
    sum += a[x][y];
    if(x == 10 && y == 10  && k == 1023)
        ans = min(ans, sum);
    DFS(x + 1, y, k, sum);
    DFS(x, y + 1, k, sum);
}
int main ()
{
    for(int i = 1; i <= 10; i++)
        for(int j = 1; j <= 10; j++)
            scanf("%d", &a[i][j]);
    DFS(1, 1, 0, 0);
    printf("%d\n", ans);
}

 

思路二:状压DP,dp[i][j][s],表示,要走(i,j)这个格子,s[0,(1<<10)-1],如果s中的第i位为1,表示到达dp[i][j][s]这个状态的时候数字i已经被访问过了,如果为0那么表示数字i没有被访问过,最后输出dp[10][10][(1<<10)-1];

 

#include<cstdio>
#include<cstring>
#include<algorithm>
const int inf = 1e9 + 10;
using namespace std;
int a[15][15];
int dp[15][15][1 << 10];
int main ()
{
    for(int i = 1; i <= 10; i++)
        for(int j = 1; j <= 10; j++)
            scanf("%d", &a[i][j]);
    memset(dp,0x3f3f3f,sizeof(dp));
    for(int i = 1; i <= 10; i++)
        for(int j = 1; j <= 10; j++)
        {
            if(i == 1 && j == 1)
            {
                dp[i][j][1 << a[i][j]] = a[i][j];
                continue;
            }
            for(int k = 1; k < (1 << 10); k++)
            {
                if(k & (1 << a[i][j]))
                {
                    if(i > 1)
                        dp[i][j][k] = a[i][j] + min(dp[i - 1][j][k - (1 << a[i][j])], dp[i - 1][j][k]);
                    if(j > 1)
                        dp[i][j][k] = min(dp[i][j][k], a[i][j] + min(dp[i][j - 1][k - (1 << a[i][j])], dp[i][j - 1][k]));
                }
            }
        }
    printf("%d\n", dp[10][10][(1 << 10) - 1]);
}

 

posted @ 2017-02-22 16:31  _Mickey  阅读(210)  评论(0编辑  收藏  举报