贪心算法(提高篇)二

1425:【例题4】加工生产调度

时间限制: 1000 ms 内存限制: 65536 KB
提交数: 2104 通过数: 544
【题目描述】
某工厂收到了 n 个产品的订单,这 n 个产品分别在 A、B 两个车间加工,并且必须先在 A 车间加工后才可以到 B 车间加工。

某个产品 i 在 A,B 两车间加工的时间分别为Ai,Bi。怎样安排这 n 个产品的加工顺序,才能使总的加工时间最短。

这里所说的加工时间是指:从开始加工第一个产品到最后所有的产品都已在 A,B 两车间加工完毕的时间。

【输入】
第一行仅—个数据 n ,表示产品的数量;

接下来 n 个数据是表示这 n 个产品在 A 车间加工各自所要的时间;

最后的 n 个数据是表示这 n 个产品在 B 车间加工各自所要的时间。

【输出】
第一行一个数据,表示最少的加工时间;

第二行是一种最小加工时间的加工顺序。

【输入样例】
5
3 5 8 7 10
6 2 1 4 9
【输出样例】
34
1 5 4 2 3
【提示】
对于100%的数据, 0 < n < 10000,所有数值皆为整数。

#include
#include
#include
#include
#define N 1005
using namespace std;

int ans[N],n,k,i,j,t,a[N];
int b[N],m[N],s[N];

void  read(){
	int i;
	cin >> n;
	for(i = 1; i <=  n; i++)
       cin  >> a[i];
       for(i = 1; i <=  n; i++)
       cin  >> b[i];
}  
void solve(){
	for(i = 1; i <= n;i++)
	{
		m[i] = min(a[i],b[i]);
		s[i] = i;
	}
	for(i = 1; i <= n-1;i++)//产品从小到大排序
	  for(j =i + 1; j<= n; j++)
	  if(m[i] >  m[j])
	  {
	  swap(m[i],m[j]);
	  swap(s[i],s[j]);
}
k = 0,t = n + 1;
for(i = 1;  i <= n;i++)//安排产品加工顺序
if(m[i] == a[s[i]])
{
	k++;
	ans[k]  = s[i];
	
}
else{
	t--;
	ans[t] = s[i];
}
k = 0 ; t = 0;//k为A加工时间,t为B加工时间
for(i = 1;  i <= n;i++){
	k += a[ans[i]];
	if(t < k) t = k;
	t += b[ans[i]];
}
cout << t << endl;
for(i = 1; i <= n; i++)
cout << ans[i] << " ";
cout << endl;
}
int  main(){
	read();
    solve();	
	return 0;
}

1426:【例题5】智力大冲浪
【题目描述】
小伟报名参加中央电视台的智力大冲浪节目。本次挑战赛吸引了众多参赛者,主持人为了表彰大家的勇气,先奖励每个参赛者m元。先不要太高兴!因为这些钱还不一定都是你的。接下来主持人宣布了比赛规则: 首先,比赛时间分为n个时段(n≤500),它又给出了很多小游戏,每个小游戏都必须在规定期限ti前完成(1≤ti≤n)。如果一个游戏没能在规定期限前完成,则要从奖励费m元中扣去一部分钱wi,wi为自然数,不同的游戏扣去的钱是不一样的。当然,每个游戏本身都很简单,保证每个参赛者都能在一个时段内完成,而且都必须从整时段开始。主持人只是想考考每个参赛者如何安排组织自己做游戏的顺序。作为参赛者,小伟很想赢得冠军,当然更想赢取最多的钱! 注意:比赛绝对不会让参赛者赔钱!

【输入】
输入共4行。

第一行为m,表示一开始奖励给每位参赛者的钱;

第二行为n,表示有n个小游戏; 第三行有n个数,分别表示游戏1~n的规定完成期限;

第四行有n个数,分别表示游戏1~n不能在规定期限前完成的扣款数。

【输出】
仅1行。表示小伟能赢取最多的钱。

【输入样例】
10000
7
4 2 4 3 1 4 6
70 60 50 40 30 20 10
【输出样例】
9950
【提示】
数据范围及提示:

n≤500,1≤ti≤n

#include 
#include
#include
#include
using namespace std;
const int MAXN = 505;
struct edge {
    int t, w;
    edge() {}
    edge(int t, int w) : t(t), w(w) {}
    bool operator < (const edge &s) const {
        return w > s.w;
    }
}p[MAXN];
bool vis[MAXN];
int main() {
    int n, m;
    scanf("%d%d", &m, &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &p[i].t);
    for (int i = 0; i < n; i++)
        scanf("%d", &p[i].w);
    sort(p, p + n);
    for (int i = 0; i < n; i++) {
        int r = p[i].t;
        while (r > 0 && vis[r])
            r--;
        if (r > 0) vis[r] = true;
        else m -= p[i].w;
    }
    printf("%d\n", m);
    return 0;
}

1430:家庭作业
【题目描述】
老师在开学第一天就把所有作业都布置了,每个作业如果在规定的时间内交上来的话才有学分。每个作业的截止日期和学分可能是不同的。例如如果一个作业学分为10,要求在6天内交,那么要想拿到这10学分,就必须在第6天结束前交。

每个作业的完成时间都是只有一天。例如,假设有7次作业的学分和完成时间如下:

作业号 1 2 3 4 5 6 7
期限 1 1 3 3 2 2 6
学分 6 7 2 1 4 5 1
最多可以获得15学分,其中一个完成作业的次序为2,6,3,1,7,5,4,注意可能d还有其他方法。

你的任务就是找到一个完成作业的顺序获得最大学分。

【输入】
第一行一个整数N,表示作业的数量。

接下来N行,每行包括两个整数,第一个整数表示作业的完成期限,第二个数表示该作业的学分。

【输出】
输出一个整数表示可以获得的最大学分。保证答案不超过longint范围。

【输入样例】
7
1 6
1 7
3 2
3 1
2 4
2 5
6 1
【输出样例】
15

#include
#include
#include
#include
#include
#include
#include
#include
#define N 1000001
using namespace std;

int n,dislike;
long long ans;
bool vis[N],f[N];

struct node
{
    int t,w;
}work[N];

bool cmp(node x,node y)
{
    return x.w  > y.w ;
}

bool pd(int x)
{
    for(int i = work[x].t ;i >= 1;i--)
    {
        if(vis[i] == 0)
        {
            vis[i] = 1;
            return 1;
        }
    }
    dislike = work[x].t ;     //不可以继续安排作业了
    return 0;
}

int main()
{
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)
        scanf("%d%d",&work[i].t ,&work[i].w );
    sort(work+1,work+n+1,cmp);
    
    memset(vis,0,sizeof(vis));
    
    for(int i = 1;i <= n;i++)
    {
        if(work[i].t < dislike) continue;  //在1~dislike区间里都不可以安排作业了
        if(pd(i)) ans += work[i].w ;
    }
    
    printf("%ld",ans);
    
    return 0;
}

你可能感兴趣的:(贪心算法(提高篇)二)