Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of homework to do. Every teacher gives him a deadline of handing in the homework. If Ignatius hands in the homework after the deadline, the teacher will reduce his score of the final test, 1 day for 1 point. And as you know, doing homework always takes a long time. So Ignatius wants you to help him to arrange the order of doing homework to minimize the reduced score.
Each test case start with a positive integer N(1<=N<=15) which indicate the number of homework. Then N lines follow. Each line contains a string S(the subject's name, each string will at most has 100 characters) and two integers D(the deadline of the subject), C(how many days will it take Ignatius to finish this subject's homework).
Note: All the subject names are given in the alphabet increasing order. So you may process the problem much easier.
2 3 Computer 3 3 English 20 1 Math 3 2 3 Computer 3 3 English 6 3 Math 6 3
2
Computer
Math
English
3
Computer
English
Math
In the second test case, both Computer->English->Math and Computer->Math->English leads to reduce 3 points, but the word "English" appears earlier than the word "Math", so we choose the first order. That is so-called alphabet order.
【题解】 题意是给你一堆作业,每个作业都有完成期限和惩罚(惩罚就是未按规定期限完成的要扣一定的分数),现在要求你计算出怎样安排做作业的顺序,可以使扣分最少,输出最少扣分数和作业顺序,扣分数相同时,输出字典序小的那个。
运用状压,n<=15,可以用二进制位来表示每个作业的完成情况,1表示完成,0表示未完成,遍历所有状态,总状态个数为2^15-1,,此时的状态就是15个1,表示所有作业都完成时是我最少扣分。
【AC代码】
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int m;
struct tree
{
int cost;//花费时间
int reduces;//最少减分
int pre;//前一个状态
}dp[1<<16];
bool vis[1<<16];//访问标志
struct no
{
char name[200];
int deadline;
int time;
}ss[16];
void output(int k)
{
int cur2=dp[k].pre^k;
int id=0;
cur2>>=1;
while(cur2)
{
id++;
cur2>>=1;
}
if(dp[k].pre!=0)
{
output(dp[k].pre);
}
printf("%s\n",ss[id].name);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&m);
for(int i=0;i<m;i++)
scanf("%s%d%d",&ss[i].name,&ss[i].deadline,&ss[i].time);
int up=1<<m;
dp[0].cost=0;//未开始做作业
dp[0].pre=-1;
dp[0].reduces=0;
memset(vis,false,sizeof(vis));
vis[0]=true;
for(int i=0;i<up-1;i++)
{
for(int j=0;j<m;j++)
{
int cur=1<<j;
if((cur&i)==0)//作业未做
{
int cur1=cur|i;
int day=dp[i].cost+ss[j].time;
dp[cur1].cost=day;
int reduce=day-ss[j].deadline;
if(reduce<0) reduce=0;
reduce+=dp[i].reduces;
if(vis[cur1])
{
if(reduce<dp[cur1].reduces)
{
dp[cur1].reduces=reduce;
dp[cur1].pre=i;
}
}
else//作业已经做了
{
vis[cur1]=true;
dp[cur1].reduces=reduce;
dp[cur1].pre=i;
}
}
}
}
printf("%d\n",dp[up-1].reduces);
output(up-1);//递归输出
}
}