#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; int i,j,k,n,m,a[503],times,sum[503][503],ans,p; int f[503][503],g[503][503]; int s[503][503],num; void dfs(int x,int len)//把工件按最低加工利用率的分配方法分开 { if (x==0||len==0) return; dfs(x-g[x][len],len-1); num++; int j=0; for (int i=x-g[x][len]+1;i<=x;i++) j++,s[num][j]=a[i]; s[num][0]=g[x][len]; } int main() { freopen("work.in","r",stdin); freopen("work.out","w",stdout); scanf("%d%d",×,&n);//times表示每个机器工作的时间,n表示工件数 for (i=1;i<=n;i++) scanf("%d",&a[i]); for (i=1;i<=n-1;i++)//预处理sum数组,sum[i][j]表示从i到j加工所需的时间 for (j=i;j<=n;j++) sum[i][j]=sum[i][j-1]+a[j]; <span style="background-color: rgb(255, 255, 255);"><span style="color:#6600cc;">sum[n][n]=a[n];//当时手残忘了处理最后一个了,T_T</span></span> memset(f,127/3,sizeof(f)); f[0][0]=0; for (i=1;i<=n;i++) f[0][i]=0; for (i=1;i<=n;i++) if (sum[1][i]+i-1<=times) { f[i][1]=(sum[1][i]+i-1-times)*(sum[1][i]+i-1-times); g[i][1]=i; } else break; for (j=2;j<=n;j++)//一共用了多少台机器 for (i=j;i<=n;i++)//当前工件区间的起点 for (k=1;k<=i-j+1;k++)//当前工件区间的长度 if (sum[i-k+1][i]+k-1<=times)//判断当前工件区间能否放在一个机器上 { int t=f[i-k][j-1]+(sum[i-k+1][i]+k-1-times)*(sum[i-k+1][i]+k-1-times); if (f[i][j]>t||f[i][j]==t&&<span style="color:#6600cc;">g[i][j]>k</span>)//这句话很重要,因为题目中说输出的方案应使工件尽量向前调度,所以后面的长度应尽量短 { f[i][j]=t; g[i][j]=k; //f[i][j]表示到工件I,用了J台机器的最低加工利用率,G[I][J]存储区间长度,便于输出 } } ans=1000000000; p=0; for (i=1;i<=n;i++) if (ans>f[n][i]) { ans=min(ans,f[n][i]); p=i; } printf("%d\n",ans); dfs(n,p); for (i=1;i<=num;i++) { for (j=1;j<=s[i][0];j++) printf("%d ",s[i][j]); printf("\n"); } return 0; }还有另一种思路,其实也比较好理解。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int dp[503][503],s[503][503],len[503],loap[503]; int i,j,k,m,n,l; void dfs(int i,int j)//用二分法不断寻找应该换机器的工件 { if (i==j) l++; else { int x; if (s[i][j]==0) for (x=i;x<=j;x++) l++; else { if (i<=s[i][j]) dfs(i,s[i][j]); loap[l+1]=1; if (s[i][j]+1<=j) dfs(s[i][j]+1,j); } } } int main() { freopen("work.in","r",stdin); freopen("work.out","w",stdout); scanf("%d%d",&m,&n); for (i=1;i<=n;i++) scanf("%d",&len[i]),dp[i][i]=len[i],loap[i]=0; for (i=1;i<n;i++) for (j=1;j<=n-i;j++) k=i+j,dp[j][k]=dp[j][k-1]+len[k]; for (i=0;i<n;i++)//i表示区间长度,dp[j][k]表示工件j到k的加工利用率 for (j=1;j<=n-i;j++) { k=i+j; int tmp=m-dp[j][k]-k+j; if (tmp<0) dp[j][k]=2000000000;//判断区间j到k能否放到一个机器上 else dp[j][k]=tmp*tmp; } for (i=0;i<n;i++) for (j=1;j<=n-i;j++) { k=i+j; for (int l=k-1;l>=j;l--) if (dp[j][l]<2000000000&&dp[l+1][k]<2000000000) if (dp[j][l]+dp[l+1][k]<dp[j][k]) dp[j][k]=dp[j][l]+dp[l+1][k],s[j][k]=l;//s[j][k]记录中间值 } printf("%d\n",dp[1][n]); l=0; dfs(1,n); for (i=1;i<=n;i++) { if (loap[i]==1) printf("\n"); printf("%d ",len[i]); } }