第一段标题

HDU1074解题报告

  HDU1074,如果仅仅从动态规划角度来看,它属于比较简单的DP问题,但是需要把问题进行转化。利用二进制构造出不同的状态,0代表课程在状态中,1表示课程不在状态中,初态全为0,终态全为1,终态的最小值即为所求结果。

  假设输入n门课程,则共有2^n个状态,对于每个状态V({i})(集合{i}表示状态V所完成的课程)需要测试是否包含所有课程,如果包含的课程(j),则根据V({i}-j)计算V({i}),此过程中使用简单的DP公式。由此可见算法复杂度为O(n*2^n),属于NP问题,题目中说明输入数据n<=15,在这种小数量级的情况下,问题还是可解的。

  题目中要求除了要输出扣掉的最小分数,还有输出课程完成的顺序。为了得到课程次序,记录下V({i})的前一个节点V({j}),{i}-{j}表示从V({j})->V({i})所添加的课程。详细代码如下:

 

#include <stdio.h>
#include <stdlib.h>
struct node{
    int cost;//到达节点所需要的时间
    int lowReduce;//到达节点减少的最小分数
    int pre;//前一个节点的编号
};
struct course{
    int deadine;
    int cost;
    char name[100];
}courses[16];
struct node *state;
void output(int index){
    int temp,id;    
    //printf("index is %d\n",index);
    if(index<=0){
        return;
    }
    output(state[index].pre);//输出前一个节点
    temp=state[index].pre^index;
    id=0;//表示课程号,temp化成二进制,从右边数第一个1的index
    temp>>=1;
    while(temp>0){
        id++;
        temp>>=1;
        //printf("id is %d\n",id);
    }
    //本节点要输出的课程名字 即(本节点所有课程名字减去前一个节点所有课程名字)
    printf("%s\n",courses[id].name);

}
int main(){
    int n,m,i,j;
    int reduce,cur;
    int stateTotal;
    scanf("%d",&n);
    while(n--){
        scanf("%d",&m);
        state=(struct node*)malloc(sizeof(struct node)*(1<<m));
        for(i=0;i<m;i++){
            scanf("%s%d%d",&courses[i].name,&courses[i].deadine,&courses[i].cost);
        }
        state[0].cost=0;state[0].lowReduce=0;state[0].pre=-1;
        stateTotal=1<<m;
        for(i=1;i<stateTotal;i++){
            state[i].cost=0;state[i].lowReduce=0x7ffffff;state[i].pre=-1;//初始化
            for(j=0;j<m;j++){
                cur=1<<j;//i 从右边数第j位
                if(i&cur){//state[i]中包括课程j
                    state[i].cost=state[i^cur].cost+courses[j].cost;//i^cur即{i}-j
                    reduce=state[i].cost-courses[j].deadine;
                    if(reduce<0)
                        reduce=0;
                    if(state[i].lowReduce>=reduce+state[i^cur].lowReduce){
                        state[i].lowReduce=reduce+state[i^cur].lowReduce;
                        state[i].pre=i^cur;//保存上一节点的编号
                    }
                }
            }
        }
        printf("%d\n",state[stateTotal-1].lowReduce);//输出最小花费
        output(stateTotal-1);
        free(state);
    }



return 0;
}

 

  程序思想比较简单,但是对二进制操作要求较高,难以理解的地方程序中已有详细注释。

posted @ 2012-08-04 21:10  小雨淅淅  阅读(1525)  评论(2编辑  收藏  举报