点击打开链接
有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>