POJ3553 Task schedule (拓扑排序+贪心+优先队列)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sdz20172133/article/details/87892602

Task schedule
Time Limit: 2000MS         Memory Limit: 65536K
Total Submissions: 306         Accepted: 193         Special Judge
Description

There are n preemptive jobs to be processed on a single machine. Each job j has a processing time pj and deadline dj. Preemptive constrains are specified by oriented graph without cycles. Arc (i,j) in this graph means that job i has to be processed before job j. A solution is specified by a sequence of the jobs. For any solution the completion time Cj is easily determined.

The objective is to find the optimal solution in order to minimize

max{Cj-dj, 0}.

Input

The first line contains a single integer n, 1 ≤ n ≤ 50000. Each of the next n lines contains two integers pj and dj, 0 ≤ pj ≤ 1000, 0 ≤ dj ≤ 1000000, separated by one or more spaces. Line n+2 contains an integer m (number of arcs), 0 ≤ m ≤ 10*n. Each of the next m lines contains two integers i and j, 1 ≤ i, j ≤ n.

Output

Each of the n lines contains integer i (number of job in the optimal sequence).

Sample Input

2
4 1
4 0
1
1 2
Sample Output

1
2
Source

Northeastern Europe 2003, Western Subregion

题意:

n个任务,每一个任务具有处理时间pj和期限dj,m对 (i   j) 表要想完成 j 任务,则先完成 i 任务)m对 (i   j) 表要想完成 j 任务,则先完成 i 任务),使得所有情况中min{max{Cj-dj, 0}}的值最小。输出一个完成任务的先后顺序,满足情况可能有多种,只要输出其中一种即可。
分析:

这题只要看出先做di越小的越好,然后用一个拓扑排序(优先选择di小的)就欧克了

证明(但我不会,网上的证明):

一、通俗点

因为对于最小的那个dj是不变的,那么如果先加工其他的,那么cj就会增大,从而cj - dj就会增大,所以要先加工dj小的。

二、严谨点

原文:https://blog.csdn.net/chm517/article/details/9291227 

假设同一时刻t有两个活动i,j可做,
先做i  s1 =max(t+pi-di,t+pi+pj-dj,0)
先做j  s2 =max(t+pj-dj,t+pi+pj-di,0)
//此处省不省略0对证明不影响只对s1,s2影响。
//举例来说,省略0是超时完成要扣钱,提前完成有奖金
//而不省略0是是超时完成要扣钱,提前完成没有事件发生
1) s1中 t+pi-di>t+pi+pj-dj
   s2中 t+pj-dj>t+pi+pj-di
   有0>pi+pj,显而不符
2)s1中 t+pi-di>t+pi+pj-dj,即-di>pj-dj   ,可推出di<dj-pj<dj
   s2中 t+pj-dj<=t+pi+pj-di 
   s2-s1=pj,显然s1<=s2
3)s1中 t+pi-di<=t+pi+pj-dj,
   s2中 t+pj-dj>t+pi+pj-di 即-dj>pi-di ,推出dj<di-pi<di
   s2-s1=-pj,显然s2<=s1
4) s1中 t+pi-di<t+pi+pj-dj
   s2中 t+pj-dj<t+pi+pj-di
   s2-s1=dj-di,结果与(2)(3)相符
因此,假设同一时刻t有两个活动i,j可做,应优先做d值小的(与p无关)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int N=50005;
vector<int> G[N];
int in[N],d[N];
vector<int>path;
int n;
int cnt;
struct node
{
    int id,d;
    friend bool operator<(node a,node b)
    {
        return b.d>a.d;
    }
}x,y;
int topo()
{
    priority_queue<node>Q;
    for(int i=1;i<=n;i++)
	{
		if(in[i]==0)
	     {
	     	x.id=i;
	     	x.d=d[i];
	     	Q.push(x);
	     }
	}
	while(!Q.empty())
	{
	    y= Q.top();
		Q.pop();
		path.push_back(y.id);
	    for(int i=0;i<G[y.id].size();i++)
		{
		     in[G[y.id][i]]--;
		     if(in[G[y.id][i]]==0)
			 {
			 	x.id=G[y.id][i];
			 	x.d=d[G[y.id][i]];
			 	Q.push(x);
			 }	
		}
	}
	  	
    
}
int main()
{
    int m;
    while(scanf("%d",&n)!=-1)
    {
    	memset(in,0,sizeof(in));
    	for(int i=0;i<=n;i++)
    		G[i].clear();
    		path.clear();
        for(int i = 1; i <= n; i++)
        {
        	int a;
            scanf("%d%d",&a,&d[i]);
        }
        scanf("%d",&m);
        while(m--)
        {
        	int a,b;
            scanf("%d%d",&a,&b);
            G[b].push_back(a);
            in[a]++;
        }
        topo();
        for(int i=n-1;i>=0;i--)
        printf("%d\n", path[i]);	
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sdz20172133/article/details/87892602