您的位置:首页 > 其它

HDU 1074 Doing Homework 状态压缩dp

2016-04-19 16:22 399 查看
点击打开链接

有n门课,每门课有截止时间和完成所需的时间,如果超过规定时间完成,每超过一天就会扣1分,问怎样安排做作业的顺序才能使得所扣的分最小

第二种方法
//那么任务所有的状态有2^n-1种
//状态方程为:Dp[next]=min{Dp[k]+i的罚时} 其中,next=k+(1<<i),k要取完满足条件的值 k>>i的奇偶性决定状态k
//具体实现为: 对每种状态遍历n项任务,如果第i项没有完成,则计算出Dp[next]的最优解

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
struct node
{
char name[110];
int dealine,spend;
}a[20];
struct NN
{
int time,score,pre,now;
}dp[1<<15+1];
int main()
{
int n,T;
while(~scanf("%d",&T))
{
while(T--)
{
scanf("%d",&n);
for(int i=0; i<n; i++)
scanf("%s%d%d",a[i].name,&a[i].dealine,&a[i].spend);

int sumstate=1<<n;
memset(dp,0,sizeof(dp));

for(int i=1;i<=sumstate;i++)
dp[i].score=INF;

/// dp[0].pre=-1;

for(int i=0; i<sumstate-1; i++)
{

//for(int j=n-1; j>=0; j--)  ///都可以
for(int j=0;j<n;j++)
{
int state=1<<j;
if((state&i)==0) ///表示state状态中没有第i个项目
{
int next=state+i;
int st=dp[i].time+a[j].spend-a[j].dealine;
if(st<0)
st=0;
if(dp[next].score>st+dp[i].score)
{
dp[next].score=st+dp[i].score;
dp[next].time=dp[i].time+a[j].spend;     ///不能用st
dp[next].pre=i;
dp[next].now=j;
}

}
}
}
stack<int>Q;
printf("%d\n",dp[sumstate-1].score);
int state=sumstate-1;

while(state)
{
Q.push(dp[state].now);
state=dp[state].pre;
}
while(!Q.empty())
{
printf("%s\n",a[Q.top()].name);
Q.pop();
}
}
}
return 0;
}


///状态方程为:Dp[next]=min{Dp[next-1<<i]+i的罚时} 枚举i与next
///具体实现为: 对每种状态遍历n项任务,如果第i项没有完成,则计算出Dp[next]的最优解

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
struct node
{
int dealine,spent;
char name[110];
}a[20];
struct N
{
int time,score,pre,now;
}dp[1<<15+1];
int main()
{
int n,T;
while(~scanf("%d",&T))
{
while(T--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%s%d%d",a[i].name,&a[i].dealine,&a[i].spent);
int sumstate=1<<n;
memset(dp,0,sizeof(dp));
for(int i=1;i<sumstate;i++)  ///此处i枚举的是后面的状态
{
dp[i].score=INF;       ///此时 i = i-state+ state;
for(int j=0;j<n;j++)
{
int state=1<<j;
if(state&i)
{
int st=dp[i-state].time+a[j].spent-a[j].dealine;
if(st<0)st=0;  ///如果在期限内就不要减分了
if(dp[i].score>dp[i-state].score+st)
{
dp[i].score=dp[i-state].score+st;
dp[i].time=dp[i-state].time+a[j].spent;
dp[i].now=j;
dp[i].pre=i-state;
}
else if(dp[i].score==dp[i-state].score+st)///此处的分数相同时 , 表示的字符串的名字按字典序输出
{
if(dp[i].now<j)///i表示后面的状态 所以此时应该让他的字典序尽可能的大,才能保证前面的尽可能小
{
dp[i].score=dp[i-state].score+st;
dp[i].time=dp[i-state].time+a[j].spent;
dp[i].now=j;
dp[i].pre=i-state;
}
}
}
}
}
stack<int>Q;
int next=sumstate-1;
printf("%d\n",dp[next].score);
while(next)
{
Q.push(dp[next].now);
next=dp[next].pre;
}
// cout<<Q.size();
while(!Q.empty())
{
printf("%s\n",a[Q.top()].name);
Q.pop();
}
}
}
return 0;
}

也可以这么写
   for(int i=1;i<sumstate;i++)
            {
                dp[i].score=INF;
                for(int j=n-1;j>=0;j--)
                
    ///i表示后面的状态 所以此时应该让他的字典序尽可能的大,才能保证前面的尽可能小, 所以按照字典序大的先枚举
                {
                    int state=1<<j;
                    if(state&i&&i>=state)
                    {
                        int st=dp[i-state].time+a[j].spent-a[j].dealine;
                        if(st<0)st=0;
                        if(dp[i].score>dp[i-state].score+st)
                        {
                            dp[i].score=dp[i-state].score+st;
                            dp[i].time=dp[i-state].time+a[j].spent;
                            dp[i].now=j;
                            dp[i].pre=i-state;
                        }
                    }
                }
            }

<span id="transmark"></span>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: