Problem: The World Final II(NEUOJ1175)排序+动态规划
The World Final is coming! Next week our seniors, Brother Head, Little Bin and God Tan will fight for the glory of NEU.
The rule of the world final is as follow:
1. if two teams have the different solved problems, then the one who have more solved problems will get higher rank;
2. if two teams have the same solved problems, then the one who have less penalty, which equals 0 initially, will get higher rank;
3. if one team get first AC of a problem, then their penalty will add a number which equal the time they first AC it, and if they tried failed k times to solve it before they AC it, then they will get more k*20 penalty;
4. the total time of the world final is 300 (including 300), and begin at time 0.
Now our seniors know how long will they solve each problem and how many times will they failed before they AC it. They wanna take a best strategy to get higher rank.
Input
There are T groups of test data. The first line contains one positive integer T (1<=T<=100).
For each test data : the first line contains an integer n(1<=n<=15), which is the number of total problems. Then follows n line, each line contains two numbers: ti and ki,(1<=ti<=300, 0<=ki<=1000) which means how long will they AC it (not the time they AC it), and how many times they failed before they AC it.
【hint】:
In the second sample input, they solve the 2nd problem firstly, then solve the 1st problem, solve they solved 2 problems in total, and penalty=(2+100*20)+(292+2*20)=2334.
Output
For each case, output one line contains two numbers separated by a space: the most number of problems they can solve, and the less penalty in that case.
Sample Input
2 2 290 2 299 1 3 290 2 2 100 299 1
Sample Output
1 319 2 2334
Source
morejarphone
Hint
No Hint!
Submit
具体题目就是这样,一共有n道题,每道题有特定的时间和固定的失败次数(这居然也能知道!!),规则acm的同学应该都能很清楚了~比赛一共300分钟,每做出一道题ac数加一,所用时间增加量为当前的时间数,每失败一次增加20分钟的罚时。(比如在一小时的时候做出一道题,用的时间就加上(60+20*失败次数))最后要看总的过题数来排名,过题数相同的所用时间越少名次越靠前。最后要求输出在规定时间内的最好情况(即过题数(最多)和所用时间(最少))。
我用的方法是01背包dp求解,背包容量是300分钟,对于一道题,更新条件是可以增加过题数或者过题数不变但是时间减小。这里还有一个问题,在使用背包前要对数据排一下序,因为如果最后通过的题目固定,那么想要让时间最少,就要把用时较少的题目排在前面,因为失败次数*20是固定罚时,和过题时间没有关系。所以对于两道用时不同的题目,一定要先做用时少的那道来保证时间最小(表示写排序的部分比较弱,偷偷用sort排序。。。不过要重载一下小于号,这个应该都会ba。。,除此以外还可以使用排序函数然后在sort里添加第三参数来执行)最后遍历一下数组找到最大的过题数(优先),和最少的使用时间,最后输出就好啦~
AC代码:
#include<iostream> #include<cstdio> #include<vector> #include<algorithm> using namespace std; class ti { public: int ft,ts; bool operator <(const ti &b)const//重载操作符 { if(ft<b.ft) return true; else return false; } }; ti dp[50]; int main() { int t; scanf("%d",&t); while(t--) { int n; int num[310]={0},time[310]={0}; int x=0,y=0x3f3f3f3f;//0x3f3f3f3f近似极大值 scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&dp[i].ft,&dp[i].ts); sort(dp+1,dp+n+1);//注意别把dp【0】排序 for(int i=1;i<=n;i++) for(int j=300;j>=dp[i].ft;j--) { if(time[j]==0) { num[j]++; time[j]=dp[i].ft+20*dp[i].ts; } else if(num[j]-num[j-dp[i].ft]==1)//过题数部不变但是时间减少的情况 { if(time[j]>time[j-dp[i].ft]+20*dp[i].ts+j) { num[j]=num[j-dp[i].ft]+1; time[j]=time[j-dp[i].ft]+20*dp[i].ts+j; } } else if(num[j]-num[j-dp[i].ft]==0)//可增加过题数的情况 { num[j]=num[j-dp[i].ft]+1; time[j]=time[j-dp[i].ft]+20*dp[i].ts+j; } // printf("%d :num%d=%d time%d=%d\n",i,j,num[j],j,time[j]); if(num[j]==x)////这一段判断时要注意先判断过题数的变化,过题数量减少的,最小时间不要变,wa了一次。。。。 y=min(y,time[j]); else if(num[j]>x) { x=num[j]; y=time[j]; } } printf("%d %d\n",x,y); } return 0; }