poj1821(단조 대기열 최적화 dp)

2315 단어 dp
제목: 선형 울타리는 N개의 연속된 널빤지로 이루어져 있다.K 명의 노동자가 있으니, 너는 그들에게 널빤지에 색칠을 하게 해야 한다.모든 노동자는 3개의 매개 변수가 있다. L은 이 노동자가 칠할 수 있는 최대 널빤지의 수를 표시하고 S는 이 노동자가 어느 널빤지에 서 있는지 나타낸다. P는 이 노동자가 널빤지 하나를 칠할 때마다 얻을 수 있는 돈을 나타낸다.주의해야 할 것은 일꾼 i는 어떤 널빤지도 칠하지 않는 것을 선택할 수 있다. 그렇지 않으면 그의 칠한 구역은 연속적인 한 단락이어야 하고 S[i]가 포함되어야 한다.마지막으로 널빤지 한 개당 한 번만 칠할 수 있다. 
문제풀이 사고방식: 이것은 단조로운 대열 최적화 dp의 문제이다. 우선 상태 dp[i][j]는 첫 번째 노동자가 닦은 마지막 널빤지가 j라는 것을 의미한다. 주의: 널빤지는 닦을 수 있고 닦지 않을 수 있으며 노동자도 어떤 벽도 닦지 않을 수 있다.이전에 나는 잊어버렸기 때문에 상태 방정식은 반만 맞췄다. dp[i][j]=max(dp[i][j], dp[i-1][k]+(j-k)*p[i]), 여기 또 dp[i][j]=max(dp[i][j], dp[i-1][j], dp[i][j][j], dp[i][j][j][j]])//제i는 개인이 닦지 않고 제j면 벽은 닦지 않는다.
여기서 관건은 방정식을 어떻게 최적화하는가이다. dp[i][j]=max(dp[i-1][k]-k*p[i])+j*p[i]를 주목하면 dp[i-1][k]-k*p[i]의 최대치를 직접 유지할 수 있다. 여기서 사용하는 것은 단조로운 대기열이다.
참조 블로그:http://www.cnblogs.com/proverbs/archive/2012/10/04/2711751.html
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

struct Node
{
	int l,p,s;
}worker[105];
int n,k,dp[105][16005],q[16005];
int head,tail,l[105],r[105];

bool cmp(Node a,Node b)
{
	return a.s < b.s;
}

int main()
{
	while(scanf("%d%d",&n,&k)!=EOF)
	{
		for(int i = 1; i <= k; i++)
			scanf("%d%d%d",&worker[i].l,&worker[i].p,&worker[i].s);	
		sort(worker+1,worker+1+k,cmp);
		for(int i = 1; i <= k; i++)
		{
			l[i] = max(worker[i].s - worker[i].l,0);
			r[i] = min(worker[i].s + worker[i].l - 1,n);
		}
		memset(dp,0,sizeof(dp));
		for(int i = 1; i <= k; i++)
		{
			for(int j = 0; j <= n; j++) dp[i][j] = dp[i-1][j]; // i        
			head = tail = 0;
			for(int j = l[i]; j < worker[i].s; j++) // dp[i-1]             
			{
				int tmp = dp[i-1][j] - j * worker[i].p;
				while(head < tail && dp[i-1][q[tail-1]] - q[tail-1]*worker[i].p <= tmp) tail--;
				q[tail++] = j;
			}
			for(int j = worker[i].s; j <= r[i]; j++)
			{
				while(head < tail && j - q[head] > worker[i].l) head++;	//          
				dp[i][j] = max(dp[i][j-1],dp[i-1][j]);
				dp[i][j] = max(dp[i][j],dp[i-1][q[head]] + (j - q[head]) * worker[i].p);
			}
			for(int j = r[i] + 1; j <= n; j++)
				dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
		}
		printf("%d
",dp[k][n]); } return 0; }

좋은 웹페이지 즐겨찾기