• BestCoder14 1002.Harry And Dig Machine(hdu 5067) 解题报告


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5067

    题目意思:给出一个 n * m 的方格,每一个小方格(大小为1*1)的值要么为 0 要么为一个正整数。规定是正整数的值得方格个数不超过 10 个。现在问从最左上角的点开始,要经过所有正整数的值的点之后,要返回到最左上角的点的最短路径是多少。

           其实为正整数的那些点具体值是什么根本无关紧要。可以先求出所有点到其他点的两两最短路径,然后利用状态压缩 (考虑到只有10个点,状态数最多为2^10)来求出答案),题解是这样说的:

          dp[i][j]:表示状态 i 的点被访问过了,当前停留在点 j 需要的最少时间。枚举另一个不在状态 i 内的点 k , 从点 j 走到点 k 的状态转移方程为:

          dp[i|(1<<k)][k] = min(dp[i|(1<<k)][k], dp[i][j] + dist(j, k))

          其中,dist[j][k] 表示从点 j 与 点 k 的最短距离。所以可以利用 bfs(当然有更简单的解法,这里我是为了练手而已) 求出以每一个点作为出发点,求出以这个点到其他所有点的最短距离。

          代码中的 dp 计算,和方程有一点点不同。有些地方不太理解,先留着吧。。。

         

      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <cstring>
      4 #include <iostream>
      5 #include <algorithm>
      6 #include <queue>
      7 using namespace std;
      8 
      9 const int maxn = 50 + 5;
     10 const int INF = 0x3f3f3f3f;
     11 int n, m, cnt, st[maxn], end[maxn];
     12 int vis[maxn][maxn], hs[maxn][maxn];
     13 int dp[maxn][1<<13], dist[maxn][maxn];
     14 
     15 int dx[] = {0, 1, 0, -1};
     16 int dy[] = {1, 0, -1, 0};
     17 
     18 struct node
     19 {
     20     int x, y;
     21     int step;
     22 } cur, tmp;
     23 
     24 queue<node> q;
     25 
     26 void bfs(int id)
     27 {
     28     while (!q.empty())
     29         q.pop();
     30     memset(vis, 0, sizeof(vis));
     31     tmp.x = st[id], tmp.y = end[id];
     32     tmp.step = dist[id][id] = 0;
     33     q.push(tmp);
     34     vis[st[id]][end[id]] = 1;
     35 
     36     while (!q.empty())
     37     {
     38         tmp = q.front();
     39         q.pop();
     40 
     41         for (int i = 0; i < 4; i++)
     42         {
     43             int tx = tmp.x + dx[i];
     44             int ty = tmp.y + dy[i];
     45             if (tx >= 1 && tx <= n && ty >= 1 && ty <= m && !vis[tx][ty])
     46             {
     47                 vis[tx][ty] = 1;
     48                 cur.x = tx;
     49                 cur.y = ty;
     50                 cur.step = tmp.step + 1;
     51                 if (hs[tx][ty] != -1)      // the target point's id
     52                     dist[id][hs[tx][ty]] = cur.step;
     53                 q.push(cur);
     54             }
     55         }
     56     }
     57 }
     58 
     59 void Init()
     60 {
     61     memset(hs, -1, sizeof(hs));
     62     int val;
     63     cnt = 0;
     64     for (int i = 1; i <= n; i++)
     65     {
     66         for (int j = 1; j <= m; j++)
     67         {
     68             scanf("%d", &val);
     69             if (val || i == 1 && j == 1)
     70             {
     71                 st[cnt] = i;
     72                 end[cnt] = j;
     73                 hs[i][j] = cnt++;  // 为每一个大于0的点(最多只有10个)编号,第一个点编号为0而不是1
     74             }
     75         }
     76     }
     77 }
     78 
     79 int main()
     80 {
     81 #ifndef ONLINE_JUDGE
     82     freopen("in.txt", "r", stdin);
     83 #endif
     84 
     85     while (scanf("%d%d", &n, &m) != EOF)
     86     {
     87         Init();
     88         for (int i = 0; i < cnt; i++)   // the shortest path from point i to other points
     89             bfs(i);                        
     90         int status = 1<<cnt;
     91         memset(dp, 0x3f, sizeof(dp));
     92         
     93         dp[0][0] = 0;
     94         for (int i = 0; i < status; i++)
     95         {
     96             for (int j = 0; j < cnt; j++)
     97             {
     98                 if (dp[j][i] != INF)
     99                 {
    100                     for (int k = 0; k < cnt; k++)
    101                     {
    102                         if (!(i & (1<<k)))   // 点k不包含在状态i上
    103                             dp[k][i|(1<<k)] = min(dp[k][i|(1<<k)], dp[j][i]+dist[j][k]);
    104                     }
    105                 }
    106             }
    107         }
    108         printf("%d
    ", dp[0][status-1]);
    109     }
    110     return 0;
    111 }

        代码中最后的输出 dp[0][status-1] 很明显就是从最左上角的点出发,经过所有正整数点的最短距离。不过为什么求的时候与二维数组dp[][]不同,这个确实不太理解。

      精简版:

      

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<vector>
     5 using namespace std;
     6 typedef long long Int;
     7 typedef pair<int,int>pi;
     8 int n,m;
     9 vector<pi>V;
    10 int Map[200][200];
    11 int dp[2058][12];
    12 int getdis(int u,int v)
    13 {
    14    if(!u)return V[v-1].first+V[v-1].second-2;
    15    u--;v--;
    16    return abs(V[v].first-V[u].first)+abs(V[v].second-V[u].second);
    17 }
    18 void up(int &x,int y)
    19 {
    20    if(x==-1||x>y)x=y;
    21 }
    22 int main()
    23 {
    24    int n,m;
    25    while(scanf("%d%d",&n,&m)!=EOF)
    26    {
    27       V.clear();
    28       for(int i=1;i<=n;i++)
    29          for(int j=1;j<=n;j++)
    30          {
    31             int u;
    32             scanf("%d",&u);
    33             if(i==1&&j==1)continue;
    34             if(u>0)
    35             V.push_back(pi(i,j));
    36          }
    37       if(!V.size()){puts("0");continue;}
    38       memset(dp,-1,sizeof(dp));
    39       dp[0][0]=0;
    40       int mx=(1<<V.size())-1;
    41          for(int j=0;j<mx;j++)
    42             for(int k=0;k<=V.size();k++)
    43               if(dp[j][k]>=0)
    44               {
    45                  for(int p=0;p<V.size();p++)
    46                     if((j&(1<<p))==0)
    47                     {
    48                        up(dp[j|(1<<p)][p+1],dp[j][k]+getdis(k,p+1));
    49                     }
    50               }
    51        int ans=-1;
    52         for(int i=0;i<V.size();i++)
    53           if(dp[mx][i+1]>=0)
    54             up(ans,dp[mx][i+1]+getdis(0,i+1));
    55        printf("%d
    ",ans);
    56    }
    57 }
    View Code
  • 相关阅读:
    「CF1051F」The Shortest Statement
    「CF911F」Tree Destruction
    「HNOI/AHOI2018」游戏
    「CF859E」Desk Disorder
    「CF858F」 Wizard's Tour
    「CF894E」 Ralph and Mushrooms
    「NOIP2018」赛道修建
    「POI2010」Bridges
    常见神经网络
    数字图像处理笔记2.22
  • 原文地址:https://www.cnblogs.com/windysai/p/4042850.html
Copyright © 2020-2023  润新知