• 第九章(二)DAG上的动态规划


    DAG上的动态规划:

    有向无环图上的动态规划是学习DP的基础,很多问题都可以转化为DAG上的最长路、最短路或路径计数问题。

    1.没有明确固定起点重点的DAG模型:

    嵌套矩形问题:有n个矩形,每个矩形可以用两个整数a、b表示它的长和宽,矩形可以嵌套在矩形中当且仅当a<c,b<d或者b<c,a<d。选出尽量多的矩形排成一行,使得除了最后一个之外,每个矩形都可以嵌套在下一个矩形内。如果有多解矩形编号字典序应尽量小。

     1 /**
     2      * 嵌套矩形问题:有n个矩形,每个矩形可以用两个整数a、b表示它的长和宽,
     3      * 矩形可以嵌套在矩形中当且仅当a<c,b<d或者b<c,a<d。选出尽量多的矩形排成一行,使得除了最后一个之外,每个矩形都可以嵌套在下一个矩形内。如果有多解矩形编号字典序应尽量小。
     4      */
     5     static int[] d= {-1,-1,-1,-1,-1,-1};
     6     static int[][]a=new int[6][6];
     7     
     8     public static void getA(ErYuan[] es) {//建立单向无环图
     9         for(int i=0;i<es.length;i++) {
    10             for(int j=0;j<es.length;j++) {
    11                 if(es[i].isOk(es[j])) {
    12                     a[i][j]=1;
    13                 }
    14             }
    15         }
    16     }
    17     
    18     public static int dp(int i) {//从i开始的最大嵌套矩形个数
    19         if(d[i]>=0) {
    20             return d[i];
    21         }
    22         d[i]=0;
    23         for(int j=0;j<d.length;j++) {
    24             if(a[i][j]==1) {
    25                 d[i]=Math.max(d[i],1+dp(j));
    26             }
    27         }
    28         return d[i];
    29     }
    30     
    31     public static void test(int i,String head) {//找到d[i]中的最大值,按字典序输出路径们
    32         head=head+i;
    33         if(d[i]==0)
    34             {
    35             System.out.println(head);
    36             }
    37         String str="";
    38         for(int j=0;j<d.length;j++) {
    39             if(a[i][j]==1&&d[i]==d[j]+1) {
    40                 test(j,head);
    41             }
    42         }
    43     }
    44     public static void main(String[] args) {
    45         Scanner scn=new Scanner(System.in);
    46         ErYuan[] es=new ErYuan[6];
    47         for(int i=0;i<6;i++) {
    48             int x=scn.nextInt();
    49             int y=scn.nextInt();
    50             es[i]=new ErYuan(x,y);
    51         }
    52         getA(es);
    53         for(int i=0;i<d.length;i++) {
    54             dp(i);
    55         }
    56         int max=0;
    57         for(int i=1;i<d.length;i++) {
    58             max=d[max]>=d[i]?max:i;
    59         }
    60         for(int i=max;i<d.length;i++) {
    61             if(d[i]==d[max]) {
    62                 test(i,"");
    63             }
    64         }
    65     }
     1 class ErYuan{
     2     int x;
     3     int y;
     4     public boolean isOk(ErYuan e) {
     5         if((x<e.x&&y<e.y)||(e.x>y&&e.y>x)){
     6             return true;
     7         }
     8         return false;
     9                 
    10     }
    11     public ErYuan(int x, int y) {
    12         super();
    13         this.x = x;
    14         this.y = y;
    15     }
    16     
    17 }

     2.固定终点的最长路和最短路

    硬币问题:有n种硬币,面值分别为v1..vn,每种都有无限多,给定非负整数S。可以选用多少个硬币,使得面值之和恰好为S?输出硬币的最小值和最大值1<=n<100,0<=S<=10000,1<=vi<=S

     1     static int[]d=new int[10];
     2     static int[]vis=new int[10];
     3     static int[]v=new int[5];
     4     /**
     5      * 硬币问题:有n种硬币,面值分别为v1..vn,每种都有无限多,给定非负整数S。
     6      * 可以选用多少个硬币,使得面值之和恰好为S?
     7      */
     8     /**
     9      * S->0的路径长度
    10      * @param S
    11      */
    12     public static int dp(int S) {
    13         if(vis[S]==1)return d[S];
    14         vis[S]=1;
    15         for(int i=0;i<vis.length;i++)if(vis[i]<=S)d[S]=Math.max(d[S], dp(S-vis[i])+1);
    16         return d[S];
    17     }

    如果要打印出来就同上,可以用递推或者储存的方式打印出来,储存的话用空间换取时间。

    3.小结

    传统的递推法可以表示成“对于每个状态i,计算f(i)",或者称为“填表法”.这需要对于每个状态i,找到f(i)依赖的所有状态。

    刷表法:对于每个状态i,更新f(i)所影响的状态。只有当每个状态所依赖的对它的影响相互独立时才能用刷表法。

  • 相关阅读:
    建网站该选择服务器还是虚拟主机
    会计基础第一章模拟试题(3)
    会计基础第一章模拟试题(2)
    13条Android手机必备技巧 让玩机更有趣
    会计基础第一章模拟试题(1)
    会计基础第二次模拟题(6)
    Foxmail邮箱最新应用指南 --如何使用「邮件标签」?
    会计基础第二次模拟题(5)
    如何使用有道云笔记的剪藏功能
    使用JSCH执行命令并读取终端输出的一些使用心得
  • 原文地址:https://www.cnblogs.com/code-fun/p/12601497.html
Copyright © 2020-2023  润新知