有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>