任务调度分配题两道 POJ 1973 POJ 1180(斜率优化复习)

POJ 1973

这道题以前做过的。今儿重做一次。由于每个程序员要么做A,要么做B,可以联想到0/1背包(谢谢N巨)。这样,可以设状态

dp[i][j]为i个程序员做j个A项目同时,最多可做多少个B项目。枚举最后一个程序员做多少个A项目进行转移(0/1)。

dp[i][j]=max{dp[i-1][k]+(time-(j-k)*a[i])/b[i]}。于是,二分时间time进行判定即可。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

int dp[110][110];
int a[110],b[110];
int n,m;

bool slove(int time){
	memset(dp,-1,sizeof(dp));
	for(int i=0;i<=m;i++){
		if(time-i*a[1]<0) continue;
		dp[1][i]=(time-i*a[1])/b[1];
	}
	for(int i=2;i<=n;i++){
		for(int j=0;j<=m;j++){
			for(int k=0;k<=j;k++){
				if(dp[i-1][k]<0||time-(j-k)*a[i]<0) continue;
				dp[i][j]=max(dp[i][j],dp[i-1][k]+(time-(j-k)*a[i])/b[i]);
			}
		}
	}
	//bool flag=false;
	for(int i=0;i<=n;i++){
		if(dp[i][m]>=m) return true;
	}
	return false;
}

int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int l=0,r=0;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++){
			scanf("%d%d",&a[i],&b[i]);
			r+=(a[i]*m+b[i]*m);
		}
		int ans=100000000;
		while(l<=r){
			int mid=(l+r)>>1;
			if(slove(mid)){
				ans=mid;
				r=mid-1;
			}
			else l=mid+1;
		}
		printf("%d\n",ans);
	}
	return 0;
}

  

POJ 1180

开始时设了二维的数组。一看范围,就知道不行了。。

可以很容易就看出是DP了。可以倒过来设状态dp[i]表示加入i任务,从i任务到n任务完成所需要的时间。

dp[i]=min{dp[j]+(s+tsum[i]-tsum[j])*fsum[i]}//i之后的第一个分组是从j开始,枚举。

这样还不足够。可以用斜率来优化。假设j<p。如果对于决策i,j更优于p,则有dp[j]+(s+tsum[i]-tsum[j])*fsum[i]<dp[p]+(s+tsum[i]-tsum[j])*fsum[i]。化简有

dp[j]-dp[p]<(tsum[j]-tsum[p])*fsum[i]。可以看到是斜率k=g[j,p]=(dp[j]-dp[p])/(tsum[j]-tsum[p])<fsum[i],j优于p。

对于k<j<p。如果有g[k,j]<g[j,p]。则j必定是可以不要的。因为当g[k,j]<s时,明显k优于j。否则g[k,j]>s,有s<g[k,j]<g[j,p]。说明,k不优于j,j不优于p。

于是,j是可以不要的。

斜率减少。因而可以去掉j。在这里,我们要维护的是斜率的下凸,如:g[k,j]>g[j,p]。这样,对于j点,如果j点可选,则其前面的点均可以不需要了。因为斜率是下凸,会直到某个斜率大于fsum[i],才会选到最优。

用一个单调队列维护即可。

#include <iostream>
#include <cstdio>
#include <algorithm>
#define LL __int64
using namespace std;

int t[10010],f[10010];
LL ts[10010],fs[10010];
int que[10010],head,tail;
LL dp[10010];

int main(){
	int n,s;
	while(scanf("%d",&n)!=EOF){
		head=tail=0;
		scanf("%d",&s);
		for(int i=1;i<=n;i++){
			scanf("%d%d",&t[i],&f[i]);
		}
		dp[n+1]=0; ts[n+1]=fs[n+1]=0;
		for(int i=n;i>=1;i--){
			ts[i]=(ts[i+1]+t[i]);
			fs[i]=(fs[i+1]+f[i]);
		}
		head=tail=0;
		dp[n+1]=0;
		que[tail++]=n+1;
		dp[n]=(s+ts[n])*fs[n];
		que[tail++]=n;
		for(int i=n-1;i>=1;i--){
			while(head<tail-1&&dp[que[head+1]]-dp[que[head]]<=(ts[que[head+1]]-ts[que[head]])*fs[i])
			head++;
			dp[i]=dp[que[head]]+(s+ts[i]-ts[que[head]])*fs[i];
			while(head+1<tail&&(dp[i]-dp[que[tail-1]])*(ts[que[tail-1]]-ts[que[tail-2]])<=(dp[que[tail-1]]-dp[que[tail-2]])*(ts[i]-ts[que[tail-1]]))
			tail--;
			que[tail++]=i;
		}
		printf("%I64d\n",dp[1]);
	}

	return 0;
}

  

时间: 2024-12-24 17:37:09

任务调度分配题两道 POJ 1973 POJ 1180(斜率优化复习)的相关文章

三分题两道:lightoj1146 Closest Distance、lightoj1240 Point Segment Distance (3D)

lightoj1146 Two men are moving concurrently, one man is moving from A to B and other man is moving from C to D. Initially the first man is at A, and the second man is at C. They maintain constant velocities such that when the first man reaches B, at

POJ 3709 K-Anonymous Sequence (斜率优化DP)

题意:有一个不递减的序列,现在要把这些数分成若干个部分,每部分不能少于m个数.每部分的权值为所有数减去该部分最小的数的和.求最小的总权值. 析:状态方程很容易写出来,dp[i] = min{dp[j] + sum[i] - sum[j] - (i-j)*a[j+1] },然而这个复杂度是 O(n^2)的肯定要TLE, 用斜率进行优化,维护一个下凸曲线,注意这个题是有个限制就是至少有要m个是连续的,所以开始的位置是2*m,想想为什么. 代码如下: #pragma comment(linker, "

POJ 3709 K-Anonymous Sequence 斜率优化

容易得出简单的递推方程如下 f[i] = min{f[j] + sum[i] - sum[j] - (i-j) *x[j+1]   } 然后发现复杂度太高 这时可以看出是一个比较经典的斜率优化 f[i] =   min{f[j] +j *x[j+1] -sum[j] -i *x[j+1]}  +sum[i] 按照http://blog.csdn.net/sdj222555/article/details/8229192 中使用的斜率优化方法推导就行了 可以发现一些单调性是比较重要的 最后需要注意

POJ 1180 斜率优化DP(单调队列)

Batch Scheduling Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 4347   Accepted: 1992 Description There is a sequence of N jobs to be processed on one machine. The jobs are numbered from 1 to N, so that the sequence is 1,2,..., N. The s

穷举(四):POJ上的两道穷举例题POJ 1411和POJ 1753

下面给出两道POJ上的问题,看如何用穷举法解决. [例9]Calling Extraterrestrial Intelligence Again(POJ 1411) Description A message from humans to extraterrestrial intelligence was sent through the Arecibo radio telescope in Puerto Rico on the afternoon of Saturday November 16

逛园子,看到个练习题,小试了一把(淘宝ued的两道小题)

闲来无事,逛园子,充充电.发现了一个挺有意思的博文,自己玩了一把. 第一题:使用 HTML+CSS 实现如图布局,border-widht 1px,一个格子大小是 60*60,hover时候边框变为橘红色(兼容IE6+,考虑语义化的结构) 效果图: 简单分析一下: 使用伪类 :hover的时候相对定位 改变z-index, 代码如下: 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta c

水了两道括号匹配

POJ 1141 给一段括号序列,要求增加最少的括号,使之合法,输出序列. dp[i][j]表示使给定序列的i到j成为合法序列所需添加的最少括号数,dp[0][length-1]即是答案,转移的话,如果s[i]和s[j]可以匹配那么dp[i][j] = dp[i+1][j-1],否则就考虑在中间选择一个位置m,使分割成的两个序列各自成为合法序列.方案的话就是多开一个数组记录然后递归输出.状态是从长度小的序列转移到长度长的序列,所以两层循环,外层枚举长度,内层枚举头位置即可.写成记忆化搜索简单一点

两道二分coming~

第一道:poj 1905Expanding Rods 题意:两道墙(距离L)之间架一根棒子,棒子受热会变长,弯曲,长度变化满足公式( s=(1+n*C)*L),求的是弯曲的高度h. 首先来看这个图: 如图,蓝色为杆弯曲前,长度为L 红色为杆弯曲后,长度为s h是所求. 又从图中得到三条关系式; (1)       角度→弧度公式  θr = 1/2*s (2)       三角函数公式  sinθ= 1/2*L/r (3)       勾股定理  r^2 – ( r – h)^2 = (1/2*

POJ 3670 &amp;&amp; POJ 3671 (dp)

最长不下降子序列的应用嘛.两题都是一样的. POJ 3670:求给定序列按递增或递减排列时,所需改变的最小的数字的数目. POJ 3671:求给定序列按递增排列时,所需改变的最小的数字的数目. 思路就是求最长不下降子序列,然后剩下的就是需要改变的字母. 最长不下降子序列:(我之前有写过,不懂请戳)http://blog.csdn.net/darwin_/article/details/38360997 POJ 3670: #include<cstdio> #include<cstring