UVa 1025

开始系统跟着刘汝佳老师的书并行刷题。

DP问题似乎很多问题是会将时间这类有序的量作为状态一个坐标,这个思路还是蛮惊奇的,建立在题目中时间是整数,并且数量级可以接受的情况。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <cmath>
using namespace std;

const int maxn= 55;
const int maxt= 205;
const int INF= 0x3f3f3f3f;
int tt[maxn], ls[maxn], rs[maxn];
int has_train[maxt][maxn][2];
int dp[maxt][maxn];

void Init(int t, int n)
{
	memset(dp, 0x3f, sizeof(dp));
	memset(tt, 0, sizeof(tt));
	memset(ls, 0, sizeof(ls));
	memset(rs, 0, sizeof(rs));
	memset(has_train, 0, sizeof(has_train));
	dp[t][n]= 0;
}
void SetHasTrain(int t, int n, int m1, int m2)
{
	int b= 0;
	for (int i= 1; i<= n-1; ++i){
		b+= tt[i-1];
		for (int d= 0; d< m1; ++d){
			if (b+ls[d]<= t){
				has_train[b+ls[d]][i][0]= 1;
			}
		}
	}
	b= 0;
	for (int i= n; i> 1; --i){
		b+= tt[i];
		for (int d= 0; d< m2; ++d){
			if (b+rs[d]<= t){
				has_train[b+rs[d]][i][1]= 1;
			}

		}
	}
}

int main(int argc, char const *argv[])
{
	int n, t, m1, m2;
	int kase= 0;

	while (1){
		scanf("%d", &n);
		if (0== n){
			break;
		}
		scanf("%d", &t);
		Init(t, n);

		for (int i= 1; i< n; ++i){
			scanf("%d", tt+i);
		}

		scanf("%d", &m1);
		for (int i= 0; i< m1; ++i){
			scanf("%d", ls+i);
		}
		scanf("%d", &m2);
		for (int i= 0; i< m2; ++i){
			scanf("%d", rs+i);
		}
		SetHasTrain(t, n, m1, m2);

		for (int i= t-1; i>= 0; --i){
			for (int j= n; j> 0; --j){
				int x= dp[i+1][j]+1;
				//left
				if (j> 1 && has_train[i][j][1] && i+tt[j-1]<= t){
					x= min(x, dp[i+tt[j-1]][j-1]);
				}
				// right
				if (j< n && has_train[i][j][0] && i+tt[j]<= t){
					x= min(x, dp[i+tt[j]][j+1]);
				}

				dp[i][j]= x;
			}
		}

		cout<<"Case Number "<<++kase<<": ";
		if (dp[0][1]>= INF){
			cout<<"impossible"<<endl;
		}
		else{
			cout<<dp[0][1]<<endl;
		}
	}

	return 0;
}
原文地址:https://www.cnblogs.com/Idi0t-N3/p/13721983.html