贪心+数据结构-poj 3110 Jenny's First Exam

题目链接:

http://poj.org/problem?id=3110

题目意思:

有n科考试,每科考试可以提前di天复习,每科考试只需一天复习,而且要求不能早于考试前di天复习。考试那天不能复习。给n科考试日期,求最晚开始复习的日期。

解题思路:

先把日期全部转化成与0000年00月00日的天数差,然后依据考试时间从晚到早排序,从后往前扫描天数,如果当前天为考试日期,则把该考试的科目加到以按最早复习时间从后往前排序的优先队列,如果当前天没有考试,则从队列中取出队头(表示最晚复习的科目),如果当前时间小于它,则表示不能完成,否则复习该科目。

PS:

1、这种贪心的方式很巧妙,按天数来处理。

2、把天数对应成日期,可以以500年为一个周期,加速处理。

详细解释的代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define Maxn 55000
int n;
int yd[2]={365,366};

int days[2][13]={0,31,28,31,30,31,30,31,31,30,31,30,31,
0,31,29,31,30,31,30,31,31,30,31,30,31};

struct DD
{
    int m,d,y;
};
struct Sub
{
    int cur,ea;
    char save[25];
    int dd;
}sub[Maxn];
bool cmp1(struct Sub a,struct Sub b) //按考试日期从晚到前排序
{
    return a.cur>b.cur;
}

int isleap(int y) //是否是润年
{
    if((y%4==0&&y%100)||(y%400==0))
        return 1;
    return 0;
}

int dtoi(int y,int m,int d) //将日期转化成距0000年00月00日的天数
{
    int res=0,yy=isleap(y);

    res+=y*365+(y-1)/4-(y-1)/100+(y-1)/400; //从第0年开始
    for(int i=1;i<m;i++)
        res+=days[yy][i];
    return res+d-1; //注意0表示第一天 1表示第2天
}

//500年一算 182621
DD itod(int cur)
{
    DD res;
    int i;

    res.y=cur/182621*500; //也从0开始记 500年为基本单位

    for(cur=cur%182621;cur>=yd[isleap(res.y)];res.y++)
        cur-=yd[isleap(res.y)];
    for(i=1;cur>=days[isleap(res.y)][i];i++)
        cur-=days[isleap(res.y)][i];
    res.m=i;
    res.d=cur+1; //由于有求于 有0所以加1

    return res;
}
struct Inf  //优先队列 按最早复习时间 从晚到前 排序
{
    int d;

    friend bool operator < (struct Inf a,struct Inf b)
    {
        return a.d<b.d;
    }
};
int main()
{
   //freopen("in.txt","r",stdin);
   //freopen("out.txt","w",stdout);
//   int sum=0;
//   for(int i=1;i<=500;i++)
//        sum+=yd[isleap(i)];
//   printf("%d\n",sum);
    //DD dd=itod(0);
   // printf("%04d.%02d.%02d\n",dd.y,dd.m,dd.d);
   while(~scanf("%d",&n))
   {
       for(int i=1;i<=n;i++)
       {
           scanf("%s",sub[i].save);
           int y,m,d;
           scanf("%2d.%2d.%4d",&d,&m,&y);
           sub[i].cur=dtoi(y,m,d);
           scanf("%d",&sub[i].dd);
           sub[i].ea=sub[i].cur-sub[i].dd;
       }
       sort(sub+1,sub+1+n,cmp1);
//       for(int i=1;i<=n;i++)
//           printf("%d ",sub[i].cur);
       priority_queue<struct Inf>myq;

       int la=sub[1].cur,s=1,e=n,le=n;
       bool ans=false;

       while(la) //从后往前扫描天数
       {
           bool ha=false;

           if(sub[s].cur==la) //如果有考试
           {
               struct Inf temp;
               temp.d=sub[s].ea;
               myq.push(temp); //把考试加到优先队列里
               ha=true;
               s++;
           }

           if(!ha)  //如果没有考试
           {
               if(!myq.empty()) //是否有考试没复习
               {
                   struct Inf temp=myq.top();
                   myq.pop();
                   if(temp.d<=la) //满足复习的条件
                        le--;
                   else
                   {
                       ans=true; //不行 肯定不能完成
                       printf("Impossible\n");
                       break;
                   }
               }
           }
           if(!le) //所有科目都复习完了
           {
               DD tt=itod(la);
               ans=true;
               printf("%02d.%02d.%04d\n",tt.d,tt.m,tt.y);
               break;
           }
           la--;
       }
       if(!ans) //可能考试重复了
            printf("Impossible\n");
   }
   return 0;
}

/*
693963 693961 693960 Impossible
*/



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值