zoj 3637 Education Manage System(dp)

题意:给出n个课的开始时间和结束时间和学分,两节课之间至少休息5分钟,问如何排课使得学分最多。

思路:其实看懂了题以后就会发现这是个简单的dp,但是时间的处理之类的东西还是挺烦的。。。把课按结束时间排序,用dp[i]表示以第i节课为结尾的排课方式最多能获得的学分,maxv[i]表示以i或小于i的课为结点为结尾的排课方式能获得的最多学分,则dp[i]=maxv[p]+dp[i],p表示能作为i的前一节课的最晚的课的id。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
int md[15]={0,31,29,31,30,31,30,31,31,30,31,30,31};
const char *Ms[13]={"","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sept","Oct","Nov","Dec"};
const int maxn=100000+10;
const int maxt=1440;
struct Classes
{
    int smon,sday,s;
    int tmon,tday,t;
    double val;
    bool operator <(const Classes &a) const
    {
        if(tmon!=a.tmon) return tmon<a.tmon;
        if(tday!=a.tday) return tday<a.tday;
        return t<a.t;
    }
}cs[maxn];
int getmon(const char *s)
{
    for(int i=1;i<=12;++i)
    {
        bool flag=true;
        for(int j=0;j<3;++j)
            if(s[j]!=Ms[i][j]) {flag=false;break;}
        if(flag) return i;
    }
    return 0;
}
int gettime(int hour,int second,const char *s)
{
    if(s[0]=='p') hour+=12;
    return hour*60+second;
}
int getdays(const char *s)
{
    int res=0;
    int i=0;
    while(s[i]>='0'&&s[i]<='9')
    {
        res=res*10+(s[i]-'0');
        i++;
    }
    return res;
}
char str[20];
double dp[maxn],maxv[maxn];
bool check(Classes a,Classes b)
{
    a.t+=5;
    if(a.t>=maxt)
    {
        a.tday++;
        a.t=a.t-maxt;
    }
    if(a.tday>md[a.tmon])
    {
        a.tday=1;
        a.tmon++;
    }
    if(a.tmon!=b.smon) return a.tmon<b.smon;
    if(a.tday!=b.sday) return a.tday<b.sday;
    return a.t<=b.s;
}
int f(int l,int r,int p)
{
    if(!check(cs[l],cs[p])) return -1;
    int ans=l;
    l++;
    while(l<r)
    {
        int m=(l+r)>>1;
        if(check(cs[m],cs[p]))
        {
            ans=m;
            l=m+1;
        }
        else r=m;
    }
    if(check(cs[r],cs[p])) ans=max(r,ans);
    return ans;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n;
    while(~scanf("%d",&n))
    {
        if(n==0)
        {
            printf("0.0\n");
            continue;
        }
        int h,s;
        for(int i=0;i<n;++i)
        {
            scanf("%s",str);
            cs[i].smon=getmon(str);
            scanf("%s",str);
            cs[i].sday=getdays(str);
            scanf("%d:%d %s",&h,&s,str);
            cs[i].s=gettime(h,s,str);

            scanf("%s",str);
            cs[i].tmon=getmon(str);
            scanf("%s",str);
            cs[i].tday=getdays(str);
            scanf("%d:%d %s",&h,&s,str);
            cs[i].t=gettime(h,s,str);
            scanf("%lf",&cs[i].val);
        }
        sort(cs,cs+n);
        dp[0]=maxv[0]=cs[0].val;
        for(int i=1;i<n;++i)
        {
            int p=f(0,i-1,i);
            if(p==-1) dp[i]=cs[i].val;
            else dp[i]=maxv[p]+cs[i].val;
            maxv[i]=max(maxv[i-1],dp[i]);
        }
        printf("%.1lf\n",maxv[n-1]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值