POJ 3762 费用流

ACM公司为提高员工效率制定新政策,员工在前K天完成任务,最高分者获得奖金。每个任务有固定时间区间和生产力得分,且员工只能同时做一件事。题目要求找出在K天内最大化生产力得分的策略。输入包含任务数N、天数K及每个任务的开始结束时间和得分,输出应为最大总得分。
摘要由CSDN通过智能技术生成
The Bonus Salary!
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 2421 Accepted: 630

Description

In order to encourage employees' productivity, ACM Company has made a new policy. At the beginning of a period, they give a list of tasks to each employee. In this list, each task is assigned a "productivity score". After the first K days, the employee who gets the highest score will be awarded bonus salary.

Due to the difficulty of tasks, for task i-th:

  • It must be done from hh_Li mm_Li : ss_Li to hh_Ri : mm_Ri : ss_Ri.
  • This range of time is estimated very strictly so that anyone must use all of this time to finish the task.

Moreover, at a moment, each employee can only do at most one task. And as soon as he finishes a task, he can start doing another one immediately.

XYY is very hard-working. Unfortunately, he's never got the award. Thus, he asks you for some optimal strategy. That means, with a given list of tasks, which tasks he should do in the first K days to maximize the total productivity score. Notice that one task can be done at most once.

Input

The first line contains 2 integers N and K (1 ≤ N ≤ 2000, 0 ≤ K ≤ 100), indicating the number of tasks and days respectively. This is followed by N lines; each line has the following format:

hh_Li:mm_Li:ss_Li hh_Ri:mm_Ri:ss_Ri w

Which means, the i-th task must be done from hh_Li mm_Li : ss_Li to hh_Ri : mm_Ri : ss_Ri and its productivity score is w. (0 ≤hh_Lihh_Ri ≤ 23, 0 ≤mm_Limm_Riss_Liss_Ri ≤ 59, 1 ≤ w ≤ 10000). We use exactly 2 digits (possibly with a leading zero) to represent hhmm and ss. It is guaranteed that the moment hh_Ri : mm_Ri : ss_Ri is strictly later than hh_Li mm_Li : ss_Li. 

Output

The output only contains a nonnegative integer --- the maximum total productivity score.

Sample Input

5 2
09:00:00 09:30:00 2
09:40:00 10:00:00 3
09:29:00 09:59:00 10
09:30:00 23:59:59 4
07:00:00 09:31:00 3

Sample Output

16

Hint

The optimal strategy is:
Day1: Task1, Task 4
Day2: Task 3
The total productivity score is 2 + 4 + 10 = 16.

Source


题意:有N个任务,每个任务有开始时间和结束时间,有自身价值,每个任务只能在固定时间段完成且占满整个时间段。每K天结算一次价值,例如今天做不了的任务,我可以留在明天同一时间段完成,问价值最大量为多少;

题解:看网上说,这道题是区间 K 覆盖。也就是区间最大覆盖量为K;
            时间点进行离散化
            设立超级源点,超级汇点,由于K天价值,图中应该限制总流量为K    
            超级源点连接最早时间点,重点连接超级汇点,容量结尾K,价值为0;
            每个点与其后面点连边,容量为INF,价值为0,保证全图联通;
            每个任务起点时间点连接终止时间点,容量为1,加之为其权值负数
            跑一遍费用流输出相反数即可
代码
#include<stdio.h>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
#define N 4005
using namespace std;
struct Node
{
   int date,value,cost,next;       
}cun[2000005];
struct ll
{
   int s,t,value;       
}cunn[N];
int list[N], dis[N], vis[N], pre[N], pr[N], tot, mark[100005], cc[N];
void add(int a,int b,int c,int d)
{
   cun[++tot].value = c;
   cun[tot].date = b;
   cun[tot].next = list[a]; 
   cun[tot].cost = d;
   list[a] = tot;
   
   cun[++tot].value = 0;
   cun[tot].cost = -d;
   cun[tot].date = a;
   cun[tot].next = list[b];
   list[b] = tot;     
}
int spfa(int s, int t)
{
   queue< int > p;
   p.push(s);
   for (int i = 1; i < 4005; i++)
   {
     dis[i] = INF;
     pre[i] = -1;
     vis[i] = 0;          
   }     
   dis[s] = 0;
   while(!p.empty())
   {
      int k = p.front();
      p.pop();
      vis[k] = 0;
      for(int i = list[k]; i; i = cun[i].next)
      {
         int date = cun[i].date;
         int value = cun[i].value;
         int w = cun[i].cost;
         if( value>0 && dis[date] > dis[k] + w)
         {
            dis[date] = dis[k] + w;
            pre[date] = k;
            pr[date] = i;
            if(!vis[date])
            {
              p.push(date);
              vis[date] = 1;              
            }    
         }
      }     
   }
  if(dis[t] >= INF)  return 0;
  return 1;   
}
int maxflow( int s, int t)
{
    int minn,num = 0;
    while(spfa(s,t))
    {
       minn = INF;
       for(int i = t; i != s; i = pre[i])
       {
           if( minn > cun[pr[i]].value )
              minn = cun[pr[i]].value;    
       }                
       for(int i = t; i != s; i = pre[i] )
       {
           cun[pr[i]].value -= minn;
           cun[ pr[i]^1 ].value += minn;        
       }
       num += dis[t];
    }
   return num;
}
int main()
{
   int n, m, a, b, c, d, e, f, k;
   while(scanf("%d%d",&n,&m)!=EOF)
      {
         int count=0;
         memset(list ,0, sizeof(list));
         memset(mark,0,sizeof(mark));
         memset(cc,0,sizeof(cc));
         tot=1;
         for(int i=0;i<n;i++)
          {
           scanf("%d:%d:%d %d:%d:%d %d",&a,&b,&c,&d,&e,&f,&k);  
           cunn[i].s=a*3600+b*60+c;
           cunn[i].t=d*3600+e*60+f;
           cunn[i].value = k;
           if(!mark[cunn[i].s])
            {
              mark[cunn[i].s]=1;
              cc[count++]=cunn[i].s;
            }
          if(!mark[cunn[i].t])
            {
              mark[cunn[i].t]=1;
              cc[count++]=cunn[i].t;                  
            }
          }   
         sort(cc,cc+count);
         int t=count+1,s=count+2,ss=count+3,tt=count+4;
         for(int i=0;i<count;i++)
          {
           mark[cc[i]]=i+1;
           add(i+1,i+2,INF,0);
          }
         for(int i=0;i<n;i++)
           add(mark[cunn[i].s],mark[cunn[i].t],1,-cunn[i].value);
         add(s,1,m,0);
         add(count,t,m,0);  
         printf("%d\n", -(maxflow(s,t)));                 
      }    
}
            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值