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;

}

 

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

你可能感兴趣的:(HDU)