hdu 1074 状态dp

本文介绍了一种使用状态动态规划方法解决学生如何合理安排作业提交顺序的问题,以最小化因延迟提交而造成的成绩损失。文章通过具体示例展示了算法实现步骤,并提供了完整的C++代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一道状态dp 题~~~~

题目链接:CLICK here

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.
 

Input
The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.
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.
 

Output
For each test case, you should output the smallest total reduced score, then give out the order of the subjects, one subject in a line. If there are more than one orders, you should output the alphabet smallest one.
 

Sample Input
  
2 3 Computer 3 3 English 20 1 Math 3 2 3 Computer 3 3 English 6 3 Math 6 3
 

Sample Output
  
2 Computer Math English 3 Computer English Math
用二进制表示事件的状态~~~比如有三门功课,用三位二进制来表示这三门功课的状态,000表示三门功课都没完成,001表示只完成了第一门功课,010表示只完成了第二门功课,100表示只完成了第三门功课,依次类推。。。。
对于本题来说~n门课程有 2^n个状态分别是从 00...0 到11...1;
我们枚举这么多种状态,然后从00...0开始遍历到11...1结束,每当遍历到一种状态的时候,就确定从当前的这种状态到另外一种状态的转移过程;
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
const int MAX=40000;
using namespace std;
struct node
{ 
 int cost;  //共花费了多少时间
 int reduce;//最少的扣分数
 int pre;//它的前一个状态
}dp[MAX];
struct node1
{
 char name[150]; //科目名称
 int deadline; //截止日期
 int cost;    //需要多少时间完成
}work[20];
bool visited[MAX]; //表示某个状态是否被访问过

void print(int k,int t) //递归输出
{
  int cnt=0;
  int v=k^t;  //用异或的形式求出对应的课程
  while(v)
  {
   v>>=1;
   cnt++;
  }
  k=t;
  t=dp[t].pre;
  if(t!=-1)print(k,t);
  printf("%s\n",work[cnt-1].name);
}

void init()
{
 dp[0].cost=0;
 dp[0].pre=-1;
 dp[0].reduce=0;
 memset(visited,false,sizeof(visited));
 visited[0]=true;
}
int main()
{
 int T,n;
 cin>>T;
 while(T--)
 {
  init();
  cin>>n;
  for(int i=0;i<n;i++)
   scanf("%s%d%d",work[i].name,&work[i].deadline,&work[i].cost);
  int upper=1<<n;
  int tupper=upper-1;
  for(int i=0;i<tupper;i++)//遍历状态
   for(int j=0;j<n;j++)   //遍历n门科目
    {
     int cur=1<<(j);  
     if((cur&i)==0) //判断当前科目有没有完成,注意(cur&i)这个括号不能丢
      {
       int curtemp=cur|i;
       int day=dp[i].cost+work[j].cost;
       int reduce=day-work[j].deadline;
       if(reduce<0)reduce=0;
       reduce+=dp[i].reduce;

       if(visited[curtemp])    //如果被访问过,那么取最优
       {
         if(reduce<dp[curtemp].reduce)
             {dp[curtemp].reduce=reduce;
              dp[curtemp].pre=i;
              dp[curtemp].cost=day;
             }
       }
       else if(!visited[curtemp])  //如果没被访问过,则更新
       {
         visited[curtemp]=true;
         dp[curtemp].reduce=reduce;
         dp[curtemp].cost=day;
         dp[curtemp].pre=i;
       }

      }
    }
    printf("%d\n",dp[tupper].reduce); //输出最终分数
    print(tupper,dp[tupper].pre); //递归输出

 }
 return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值