幫助BSNY(狀態壓縮+4維dp+滾動數組)
阿新 • • 發佈:2017-09-28
string scan ++ cstring pac str != return 改變
懵逼題,一度推出六維的DP,最後看了題解。。
恍然大悟。。。(需要運用好題目的限制(a[i]>=25 且a[i]<=32))並將相同的a[i]進行壓縮,壓縮成一個值
因為拿出一本書只有兩種可能,(1)放到最前面,(2)放到與它相同編號的書的旁邊,那麽我們可以就此加上限制,就可以推出狀態轉移方程式了(PS:每次拿書必須是一團一團地取出來,否則並不改變原狀態)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #definell long long using namespace std; ll n,k,a[10005],h[100005],x,ans,flag[100005],sum[10005],f[2][105][10][1<<8],tot,all,p[10005]; int main(){ scanf("%lld%lld",&n,&k); for (int i=1; i<=n; i++) scanf("%lld",a+i),a[i]-=24; for (int i=1; i<=n; i++) { if (a[i]!=a[i-1]) h[++tot]=a[i]; sum[tot]++; } for (int i=tot; i; i--){ if (flag[h[i]]) p[i]=1; flag[h[i]]=1; } memset(f[0],127,sizeof(f[0])); f[0][0][0][0]=0; all=(1<<8)-1; for (int i=1; i<=tot; i++) { x=x^1; memset(f[x],127,sizeof(f[x])); for (int j=0; j<=k; j++)for (int w=0; w<=8; w++) for (int m=0; m<=all; m++) { if (f[x^1][j][w][m]>n) continue; f[x][j][h[i]][m|(1<<(h[i]-1))]=min(f[x][j][h[i]/*當前的最後一位是h[i]*/][m|(1<<(h[i]-1))],f[x^1][j][w][m]+(h[i]!=w));//當前的狀態等於之前的狀態+(判斷此時掃描的位是否等於原先的最後一位) if (j+sum[i]>k) continue; f[x][j+sum[i]][w][m|(1<<(h[i]/*將所有的相同值的合並後得到的*/-1)/*h[i]-1表示h[i]是否被取過了,與mor一下表示當前的狀態*/)]=min(f[x][j+sum[i]][w][m|(1<<(h[i]-1))],f[x^1][j][w][m]+!(m&(1<<(h[i]-1)))); if (p[i]) f[x][j+sum[i]/*改變為j+sum[i]次之後的狀態*/][w][m]=min(f[x][j+sum[i]/*改變為j+sum[i]次之後的狀態*/][w][m],f[x^1][j][w][m]); } } //每次x進行^操作是為了創造出滾動數組,即本次的狀態只跟上一次的狀態有關 ans=124278904761894269; for (int i=0; i<=k; i++) for (int w=0; w<=8; w++) for (int m=0; m<=all; m++) ans=min(ans,f[x][i][w][m]); printf("%lld\n",ans); return 0; }
幫助BSNY(狀態壓縮+4維dp+滾動數組)