石子合並及優化


  1.石子歸並

非常朴素,順着推即可

w [ i ] [ j ] 表示把第i堆到第j堆的石子和到一起的最后一步的代價

f [ i ] [ j ] = min{f [ i ] [ k ] + f [ k+1 ] [ j ] + w[ i ] [ j ] | i <= k < j , i <= j}

for(int i=1;i<=n;++i)//長度 for(int j=1;j+i<=n+1;++j)//起點 { int e=j+i-1; for(int k=j;k<e;++k)//分割點 { dp1[j][e]=min(dp1[j][k]+dp1[k+1][e]+sum[e]-sum[j-1],dp1[j][e]); } }

  2.[NOI1995]石子合並

  在上面那個問題略微變動一下,變成了環形,可以將其暴力拆成鏈

void read() { memset(dp1,0x3f,sizeof(dp1)); red(n); for(int i=1;i<=n;++i) { red(a[i]); a[i+n]=a[i]; } } void work() { for(int i=1;i<=2*n;++i) { sum[i]=sum[i-1]+a[i]; dp1[i][i]=0; } for(int i=1;i<=n;++i) for(int j=1;j+i<2*n;++j) { int e=j+i-1; for(int k=j;k<e;++k) { dp1[j][e]=min(dp1[j][k]+dp1[k+1][e]+sum[e]-sum[j-1],dp1[j][e]); dp2[j][e]=max(dp2[j][k]+dp2[k+1][e]+sum[e]-sum[j-1],dp2[j][e]); } } minn=INF; for(int i=1;i<=n;++i) { minn=min(minn,dp1[i][i+n-1]); maxx=max(maxx,dp2[i][i+n-1]); } printf("%d\n%d",minn,maxx); }

  3.四邊形優化

  上面的朴素寫法復雜度都是O(n^3),有沒有更好的寫法嗎?

  有,利用數學里的四邊形不等式

  f[a][c]+f[b][d]<=f[b][c]+f[a][d]

  交叉小於包含,即交叉的兩個區間,a到c和b到d的值滿足小於等於包含的兩個區間[bc包含於ad])
  則說這個東西滿足四邊形不等式

   簡而言之,就是該區間的最優分割點一定在前一個區間和后一個區間之間,即:

  s [ i ] [ j - 1 ] <= s [ i ] [ j ] <= s [ i + 1 ] [ j ]

  

for(int i=1;i<=n;++i) for(int j=1;j+i<2*n;++j) { int e=j+i-1; for(int k=r[j][e-1];k<=r[j+1][e];++k) { if(dp1[j][e]>dp1[j][k]+dp1[k+1][e]+sum[e]-sum[j-1]) { dp1[j][e]=dp1[j][k]+dp1[k+1][e]+sum[e]-sum[j-1]; r[j][e]=k; } } }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM