URAL1031

URAL1031

这道题是动态规划,我霸王硬上弓,写了个ON4)的算法,居然WA啦。看讨论里有ON)算法的解,想了半天没想出来。后来读的别人代码,唉,深感这是一道好题,我没有认真思考。

假设i为当前的车站,index1index2index3是与车站i的距离分别小于等于L1L2L3 最远的三个车站编号,则有动态规划公式:

pricesi)= minpricesindex1)+C1, pricesindex2)+C2, pricesindex3)+C3

我觉得这个公式的推导比较复杂:

在最优解中,一旦在某车站A买了一张票,假设价格为C1,则可以用这张车票一直乘坐到离A的距离都小于等于L1的所有车站(结论1)。

由于结论1”,可以证明距离目标车站A小于等于L1中最远的那个车站到A的价格,是所有距离A小于等于L1的车站中价格最小的(或与其它车站价格相同)(这个结论需要稍作思考,在此不赘述)。同理适用于L2L3.所以对于距离A小于等于L3的所有车站,公式成立。

对与距离A大于L3的车站:假设距离A小于等于L3的最远车站为B,假设CA的距离大于L3,则从C车站到B,要么价格相等,要么购买一张新票,所以prices(C) + prices(C,A)<=prices(C)+C3

从而可以得出推导公式。

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StreamTokenizer;


public class URAL1031 {
	static {
        System.setIn(URAL1031.class.getResourceAsStream("/URAL1031.txt"));
    }
    private static PrintWriter stdout = new PrintWriter(System.out);
    private static StreamTokenizer stdin = new StreamTokenizer(new InputStreamReader(System.in));
    
    
    private static long L1;
    private static long L2;
    private static long L3;
    private static long C1;
    private static long C2;
    private static long C3;
    private static int N;
    private static int M;
    private static int START;
    private static int END;
    private static long[] distance;
    private static long[][] prices;
	/**
	 * @param args
	 */
	public static void main(String[] args) throws IOException {
		readData();
		cal();
	}
	
	private static void readData() throws IOException  {
		L1 = readInt();
		L2 = readInt();
		L3 = readInt();
		C1 = readInt();
		C2 = readInt();
		C3 = readInt();
		N = readInt();
		START = readInt();
		END = readInt();
		if (START > END) {
			int buf = START;
			START = END;
			END = buf;
		}
		START -= 1;//start from 0, not 1
		END -= 1;
		
		distance = new long[END - START + 1];
		distance[0] = 0;
		for (int i = 0; i < START - 1; i++) {
			readInt();//ignore
		}
		int startDistance = readInt();
		for (int i = 0; i < END - START; i++) {
			int d = readInt();
			distance[i + 1] = d - startDistance;
		}
		
		M = END - START + 1;
		prices = new long[M][M];
		for (int i = 0; i < M; i++) {
			for (int j = i + 1; j < M; j++) {
				prices[i][j] = calPrice(i, j);
				prices[j][i] = prices[i][j];
			}
		}
	}
	
	private static void cal() {
		//printMatrix();
		for (int k = 2; k <= M - 1; k++) {
			for (int i = 0; i < M; i++) {
				for (int j = i + k; j < M; j++) {
					long min = prices[i][j];
					for (int x = i + 1; x < j; x++) {
						long p = prices[i][x] + prices[x][j];
						if (p < min) {
							prices[i][j] = p;
							prices[j][i] = p;
							min = p;
						}
					}
				}
			}
		}
		//printMatrix();
		stdout.println(prices[0][M - 1]);
		stdout.flush();
	}
	
	private static int readInt() throws IOException {
        stdin.nextToken();
        return (int) stdin.nval;
    }
	
	private static long calDistance(int i, int j) {
		long d = distance[j] - distance[i];
		if (d < 0) {
			return 0 - d;
		} else {
			return d;
		}
	}
	
	private static long calPrice(int i, int j) {
		if (i == j) {
			return 0;
		}
		long d = calDistance(i, j);
		if (d <= L1) {
			return C1;
		} else if (d <= L2) {
			return C2;
		} else if (d <= L3) {
			return C3;
		}
		return Integer.MAX_VALUE;
	}
	
	
	private static void printMatrix() {
    	System.out.print("     ");
        for (int i = 0; i < M; i++) {
        	System.out.print(t(i));
        }
        System.out.println();
        for (int i = 0; i < M; i++) {
        	System.out.print(t(i));
        	for (int j = 0; j < M; j++) {
        		System.out.print(t(prices[i][j]));
        	}
        	System.out.println();
        }
    }
    
    private static  String t(long i) {
    	if (i >= Integer.MAX_VALUE) {
    		return "     ";
    	}
    	if (i < 10) {
    		return "    " + i;
    	} else if (i >= 10 && i <= 99) {
    		return "   " + i;
    	}
    	return "  " + i;
    }

}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值