SW练习_捡两次废纸_范贤捡废纸

思路:和捡一次的思路一样,变化的部分是,因为需要进行第二次捡拾,第一次捡拾的路径需要被记录。

实现的时候,把每一个节点的父亲节点保存一下,第一次捡完后,从最后一个节点回溯下,父亲路径上的废纸清除。

疑问:两次局部最优解,是否是全局最优解?因为代码没提交,只检查了两个用例,无法确定

package info.frady.dp;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
2020.03.22
* 可以行走,有废纸
。可以行走,但没有废纸
#不可以行走

2
9 7
*........
.....**#.
..**...#*
..####*#.
.*.#*.*#.
...#**...
*........
5 5
.*.*.
*###.
*.*.*
.###*
.*.*.

 7
 8

1
5 5
.*.*.
*###.
*.*.*
.###*
.*.*.
 */
public class 捡两次废纸_范贤捡废纸 {
    public static void main(String[] args) throws Exception{
        BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
        int T=Integer.parseInt(reader.readLine());//测试用例的个数
        for (int i = 0; i < T; i++) {
            String str=reader.readLine();
            int L=Integer.parseInt(str.split(" ")[0]);//存放数据的列
            int H=Integer.parseInt(str.split(" ")[1]);//存放数据的行
            char [][] arr1=new char[H][L];//存放数据的开始状态
            char [][] arr2=new char[H][L];//存放纸片被捡走后,第二次的数据状态

            for (int j = 0; j <H ; j++) {
                str=reader.readLine();
                for (int k = 0; k <L ; k++) {
                    arr1[j][k]=str.charAt(k);
                    arr2[j][k]=str.charAt(k);
                }
            }
            int f1=process(arr1,arr2);
            int f2=process(arr2,arr1);
            System.out.println(f1+f2);

        }

        reader.close();

    }

    private static int process(char[][] arr1,char[][] arr2) {


        int H=arr1.length;
        int L=arr1[0].length;
        int [][] r=new int[H][L];
        int[][] ph=new int[H][L];//保存当前节点的父亲节点
        int[][] pl=new int[H][L];//保存当前节点的父亲节点

        for (int j = 0; j < H; j++) {//行
            for (int k = 0; k < L; k++) {//列
                int l=0;
                int u=0;
                if(k-1>=0 ){//左侧有数据
                    l= r[j][k-1];
                }
                if(j-1>=0 ){//上方有数据
                    u= r[j-1][k];
                }
                if(arr1[j][k]=='#'){
                    r[j][k]=-Integer.MAX_VALUE;
                }else{//当前不是死路,需要选择最好的路径
                    int max=0;
                    if(l>=u){//左侧的数据大,选择左侧的数据,路径从左侧来
                        max=l;
                        ph[j][k]=j;//父节点所在的行
                        pl[j][k]=k-1;

                    }else{//上方数据比较大,选择上方的数据,道路从上方来
                        max=u;
                        ph[j][k]=j-1;//父节点所在的行
                        pl[j][k]=k;
                    }

                    if(arr1[j][k]=='*' ) {//有废纸
                        r[j][k]=max+1;
                    }else{
                        r[j][k]=max;
                    }
                }

            }

        }

        //需要把最长的路径上的废纸捡掉,用arr1捡掉后,生成arr2
        arr2[arr2.length-1][arr2[0].length-1]='.';//最后一个点肯定被访问到
        arr2[0][0]='.';//第一个点肯定被访问到
        int m=H-1;
        int n=L-1;
        while(m!=0 && n!=0){
            arr2[ph[m][n]][pl[m][n]]='.';
            m=ph[m][n];
            n=pl[m][n];
        }
        return r[r.length-1][r[0].length-1];
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值