noip 2006 提高组


环状处理+区间dp得解,注意答案需要枚举判断出以哪一颗珠子开始最大。

状态转移方程为:

dp[j][i] = max(E[j]*E[k+1]*E[i+1]+dp[j][k]+dp[k+1][i],dp[j][i])

j是开始的一颗珠子,i是结束的一颗珠子。

相当于用k截开每两颗珠子计算最大区间值。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define din(x) scanf("%lf",&x)
#define dout(x) printf("%lf",x) 
#define in(x) scanf("%d",&x)
#define lin(x) scanf("%lld",&x)
#define out(x) printf("%d",x)
#define lout(x) printf("%lld",x)
#define sin(x) scanf("%s",x)
#define chin(x) scanf("%c",&x)
#define sout(x) printf("%s",x)
#define chout(x) printf("%c",x)
#define ko putchar(' ')
#define ex putchar('\n')
const int MAXN = 105;

int n;
int dp[MAXN*2][MAXN*2];
int E[MAXN*2];

int main()
{
	in(n);
	for(int i = 1;i <= n;i++)
	{
		in(E[i]);
		E[i+n] = E[i];
	}
	
	E[0] = E[n];
	
	for(int i = 1;i <= 2*n;i++)
	{
		for(int j = i;j >= 1 && j > i-n;j--)
		{
			for(int k = j;k < i;k++)
			{
				dp[j][i] = max(E[j]*E[k+1]*E[i+1]+dp[j][k]+dp[k+1][i],dp[j][i]);
			}
		}
	}
	int ans = 0;
	for(int i = 1;i <= n;i++)
	{
		ans = max(dp[i][i+n-1],ans);
	}
	out(ans);
	return 0;
} 


一道典型的分组背包题。

相当于01背包中加了一堆“附件”,实质上代码相当于枚举每个主件,看是取一个主件就好,还是取主件和其第一个附件,还是取主件和其第二个附件,亦或者是全都要(主件及其第一,二个附件)。

状态转移方程就是依照上面思路走的,直接套01模板就行:

                if(j >= a[i]) f[j] = max(f[j],f[j-a[i]] + a[i]*h[i]);
if(j >= a[i] + a1[i]) f[j] = max(f[j],f[j - a[i] - a1[i]] + a[i]*h[i] + a1[i]*h1[i]);
if(j >= a[i] + a2[i]) f[j] = max(f[j],f[j - a[i] - a2[i]] + a[i]*h[i] + a2[i]*h1[i]);
if(j >= a[i] + a1[i] + a2[i]) f[j] = max(f[j],f[j-a[i]-a1[i]-a2[i]] + a[i]*h[i] + a1[i]*h1[i] + a2[i]*h2[i]);

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
#define din(x) scanf("%lf",&x)
#define dout(x) printf("%lf",x)
#define lin(x) scanf("%lld",&x)
#define in(x) scanf("%d",&x)
#define sin(x) scanf("%s",x)
#define chin(x) scanf("%c",&x)
#define out(x) printf("%d",x)
#define lout(x) printf("%lld",x)
#define sout(x) printf("%s",x)
#define ex putchar('\n') 
#define ko putchar(' ')
const int MAXN = 100;
int a[MAXN],a1[MAXN],a2[MAXN];
int h[MAXN],h1[MAXN],h2[MAXN];
int f[32005];
int n,m;	

void dp()
{
	for(int i = 1;i <= m;i++)
	{
		for(int j = n;j >= a[i];j--)
		{
			if(j >= a[i]) f[j] = max(f[j],f[j-a[i]] + a[i]*h[i]);
			if(j >= a[i] + a1[i]) f[j] = max(f[j],f[j - a[i] - a1[i]] + a[i]*h[i] + a1[i]*h1[i]);
			if(j >= a[i] + a2[i]) f[j] = max(f[j],f[j - a[i] - a2[i]] + a[i]*h[i] + a2[i]*h1[i]);
			if(j >= a[i] + a1[i] + a2[i]) f[j] = max(f[j],f[j-a[i]-a1[i]-a2[i]] + a[i]*h[i] + a1[i]*h1[i] + a2[i]*h2[i]);
		}
	}
}

int main()
{
//	freopen("budget.in","r",stdin);
//	freopen("budget.out","w",stdout);
	in(n);in(m);
	for(int i = 1;i <= m;i++)
	{
		int v,p,q;
		in(v);in(p);in(q);
		if(q == 0)
		{
			a[i] = v;
			h[i] = p;
		}
		else
		{
			if(!a1[q])
			{
				a1[q] = v;
				h1[q] = p;
			}
			else
			{
				a2[q] = v;
				h2[q] = p;
			}
		}
	}
	dp();
	out(f[n]);
	return 0;
}



一道题意十分复杂的模拟题,实际上并没有用什么特别的算法,就是单纯的模拟。

意思大概是:

   1、给了n个工件,每个工件要在总共m个机器上每个机器处理一次。

    2、给了工件放上去的顺序,但注意不是时间顺序

    3、每个工件每次处理都有一个指定的机器,所需的时间,处理工序必须按给的机器顺序。

    4、(划重点)前面的工件(设为1号)若处理时间很长,长到足以让下面一个需要在某一个机器上处理的工件(设为2号)所需时间比1号在另一机器上处理的时间还要短的话,由于一号虽然接下来要在此机器上处理,但由于上一次处理还没有完,于是2号就可以先于一号在此机器上处理(反正影响不到1号)。

理解了上面的就可以写出这样的代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
#define din(x) scanf("%lf",&x)
#define dout(x) printf("%lf",x)
#define lin(x) scanf("%lld",&x)
#define in(x) scanf("%d",&x)
#define sin(x) scanf("%s",x)
#define chin(x) scanf("%c",&x)
#define out(x) printf("%d",x)
#define lout(x) printf("%lld",x)
#define sout(x) printf("%s",x)
#define ex putchar('\n') 
#define ko putchar(' ')
const int MAXN = 25;
const int len = 500;
int n,m;
int ans = 0;
int a[len],rank[len];
int mac[MAXN][MAXN],t[MAXN][MAXN],cnt[MAXN];
int last[MAXN];
bool worked[MAXN][len];

bool check(int from,int lasttime,int id)
{
	for(int i = from;i < from + lasttime;i++)
	{
		if(worked[id][i])
		{
			return 0;
		}
	}
	return 1;
}

int main()
{
	in(m);in(n);
	int all = n*m;
	for(int i = 1;i <= all;i++)
	{
		in(a[i]);
		cnt[a[i]]++;
		rank[i] = cnt[a[i]];
	}
	for(int l = 1;l <= 2;l++)
	{
		for(int i = 1;i <= n;i++)
		{
			for(int j = 1;j <= m;j++)
			{
				if(l == 1)
					in(mac[i][j]);
				else
					in(t[i][j]);
			}
		}
	}
	
	for(int i,j = 1;j <= all;j++)
	{
		int idx = a[j];
		int id = mac[idx][rank[j]];
		for(i = last[idx] + 1;;i++)
		{
			if(!worked[id][i])
			{
				if(check(i,t[idx][rank[j]],id))
				{
					break;
				}
			}
		}
		int end = i + t[idx][rank[j]]-1;
		for(i;i <= end;i++)
		{
			worked[id][i] = 1;
		}
		last[idx] = end;
		ans = max(ans,end);
	}
	out(ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/chang_yl/article/details/80473040