题目链接:
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 */