zoukankan      html  css  js  c++  java
  • UVA

    传送门:https://vjudge.net/problem/UVA-10564

    题目大意:给你一张形如沙漏一般的图,每一个格子有一个权值,问你有多少种方案可以从第一行走到最后一行,并且输出起点最靠前的方案,以及此方案的起点编号,起点相同则字典序最小。

    题解:

      很容易想到一个DP,dp[i][j][S]代表到第i层,第j列,从第一层到这里的路径和为S的方案数,最后只要查询最后一行的方案数即可了。但是这样很不好输出方案!我们可能需要从终点向上dfs,但是又无法保证起点编号最小以及字典序最小。但是我们能从终点向上dfs,那么如果我们反过来DP呢?可行啊,这样就可以从起点向终点dfs了,贪心选择可行的路径即可。
      需要注意的是上下两个一半的沙漏的转移一个是到j与j+1,一个是j与j-1,要考虑清楚细节!

     1 #include<queue>
     2 #include<cstdio>
     3 #include<vector>
     4 #include<cstring>
     5 #include<iostream>
     6 #include<algorithm>
     7 #define RG register
     8 #define LL long long
     9 #define fre(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
    10 using namespace std;
    11 const int MAXN=22,MAXS=599;
    12 int n;
    13 LL ans,S;
    14 LL a[MAXN*2][MAXN],dp[MAXN*2][MAXN][MAXS];
    15 void dfs(int x,int y,int sum);
    16 int main()
    17 {
    18    while(scanf("%d%lld",&n,&S)!=EOF)
    19       {
    20          if(n+S==0)break;
    21          for(int i=1;i<=n;i++) for(int j=1;j<=n-i+1;j++) scanf("%lld",&a[i][j]);
    22          for(int i=n+1;i<2*n;i++) for(int j=1;j<=i-n+1;j++) scanf("%lld",&a[i][j]);
    23          memset(dp,0,sizeof dp);
    24          for(int i=1;i<=n;i++) dp[n*2-1][i][a[n*2-1][i]]=1;
    25          for(int i=n*2-2;i>=n;i--)
    26             for(int j=1;j<=i-n+1;j++)
    27                for(int k=0;k<=S;k++)
    28                   {
    29                      if(dp[i+1][j][k] && k+a[i][j]<=S) dp[i][j][k+a[i][j]]+=dp[i+1][j][k];
    30                      if(dp[i+1][j+1][k] && k+a[i][j]<=S) dp[i][j][k+a[i][j]]+=dp[i+1][j+1][k];
    31                   }
    32          for(int i=n-1;i>=1;i--)
    33             for(int j=1;j<=n-i+1;j++)
    34                for(int k=0;k<=S;k++)
    35                   {
    36                      if(dp[i+1][j][k] && k+a[i][j]<=S) dp[i][j][k+a[i][j]]+=dp[i+1][j][k];
    37                      if(dp[i+1][j-1][k] && k+a[i][j]<=S) dp[i][j][k+a[i][j]]+=dp[i+1][j-1][k];
    38                   }
    39          ans=0; for(int i=1;i<=n;i++) ans+=dp[1][i][S]; printf("%lld
    ",ans);
    40          for(int i=1;i<=n;i++)
    41             if(dp[1][i][S])
    42                {
    43                   printf("%d ",i-1);
    44                   int x=1,y=i,sum=S;
    45                   while(x<n*2-1)
    46                      {
    47                         if(x<n)
    48                            {
    49                               if(dp[x+1][y-1][sum-a[x][y]])  sum-=a[x][y],y--,printf("L");
    50                               else sum-=a[x][y],printf("R");
    51                            }
    52                         else
    53                            {
    54                               if(dp[x+1][y][sum-a[x][y]]) sum-=a[x][y],printf("L");
    55                               else sum-=a[x][y],y++,printf("R");
    56                            }
    57                         x++;
    58                      }
    59                   break;
    60                }
    61          printf("
    ");
    62       }
    63    return 0;
    64 }
  • 相关阅读:
    时间复杂度与数据规模估计
    类型总结——数组前序和
    pat B1018——锤子剪刀布(数字替换字母思想)
    Linux下Tomcat(3):修改默认的8080端口号
    MySQL 重复数据的简单处理方式
    MySQL 排序
    MySQL DATE类型
    MySQL BETWEEN运算符介绍
    数据库简介
    在Linux下设置Kettle的定时任务
  • 原文地址:https://www.cnblogs.com/D-O-Time/p/7701377.html
Copyright © 2011-2022 走看看