ワークスケジュール

5239 ワード

3、ワークスケジューリング(work.pas/c/cpp)【問題の説明】Jamの工場に新たに商品が入ってきたので、急いで加工する必要があります.工場にはたくさんの加工機械があります.これらの貨物には余裕がありますが、加工方法を合理的に手配して、各加工機械を十分に利用させたいと思っています.例えば、彼はワークを8時間以内に加工して完成させることを望んでいます.ここに5つのワークがあることが知られています.順序によって、消費する時間は次は5 2 4 4 3、つまり5つのワークが8時間以内に完成しなければならない.もちろん、それぞれ5台の加工機械で完成するようにスケジューリングすることができますが、1台の機械ごとに3 6 4 4 5時間空いているので、機械の加工利用率は低くなります.ここでは、残りの時間の二乗と、あなたがスケジューリングした加工利用率、すなわち32+62+42+42+52=102を表します.もちろん、Jamはこの値が小さいほど良いことを望んでいます.そうすれば、機械を十分に利用することができます.また、同じ機械で1つのワークを加工した後、1時間休む必要があります.ワークの加工は所定の順序で入力されますので、注意してください:1.加工の順序は所定の後のワークを前に持って加工することができなくて、図の中の2と3のように位置を変えることができなくて、順番に所定の順序でスケジューリングするしかありません.この点に注意してください.
2.休憩時間はl時間です.この例では、Jamが7時間以内に完了するように要求した場合、5番ワークは別の機械で完了しなければなりません.もちろん、Jamは最も長い時間を消費するワークよりも韻時間が長いことを保証します.そうしないと解けません. 
3.機械の数が無限であることを見ることができます.1つのスケジューリングについて、いくつかの機械加工が必要であれば、総効率が最も高く、つまり効率値が最も小さい限り.
4.いかなるワークも前に手配すべきで、ワークが完成した後にしか空き時間を残すことができなくて、この点、図の中にも体現があります. 
【入力ファイル】(work.in)
入力ファイルの1行目はJamが完成を要求した時間とワークの数2行目はそれぞれ1番ワークに必要な時間、2番ワークに必要な時間…入力順は所定の順序
【出力ファイル】(work.out)出力ファイルは2行で、第1動作が最小の効率値であり、第2行から以下がスケジューリングスキームである.
【入力サンプル】
8 5
5 2 4 4 3 
【出力サンプル】
10
5
2 4 
4 3 
【注釈】出力する方案はワークをできるだけ前にスケジューリングすること.例えば:
入力の場合
8 3
5 2
5
出力は

5 2 

ではなく
9

2  5
【データ規模】40%のデータに対して、ワーク数<10 Jam要求時間<30 100%のデータに対して、ワーク数<500 Jam要求時間<30000データ保証効率値がロング整数範囲内
【データ規模】40%のデータに対して、ワーク数<10 Jam要求時間<30 100%のデータに対して、ワーク数<500 Jam要求時間<30000データ保証効率値がロング整数範囲内
この問題にはいろいろな解法があるようですが、試験の時の考えから話しましょう.この問題を見てまず思いついたのが区間DPです.しかし、当時は頭の悪いミスを犯してACができなかったので、試して修正したコードです.
#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",&times,&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
",ans); dfs(n,p); for (i=1;i<=num;i++) { for (j=1;j<=s[i][0];j++) printf("%d ",s[i][j]); printf("
"); } 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
",dp[1][n]); l=0; dfs(1,n); for (i=1;i<=n;i++) { if (loap[i]==1) printf("
"); printf("%d ",len[i]); } }

小編雲:動き回るには必ず脳がはっきりしなければならない.手が不自由な+脳が不自由ではない.もちろん考えないでください.