洛谷 P3190 [HNOI2007]神奇遊樂園 解題報告
阿新 • • 發佈:2018-12-20
P3190 [HNOI2007]神奇遊樂園
Description
給你一個 \(m * n\) 的矩陣,每個矩陣內有個權值\(V(i,j)\) (可能為負數),要求找一條迴路,使得每個點最多經過一次,並且經過的點權值之和最大。
Input
輸入檔案中的第一行為兩個正整數\(n\)和\(m\),表示遊樂場的大小為\(n*m\)。因為這個娛樂場很狹窄,所以\(n\)和\(m\)滿足:\(2\le n\le 100\),\(2\le m\le 6\)。接下來的\(n\)行,每行有\(m\)個整數,第\(i\)行第\(j\)列表示遊樂場的第\(i\)行第\(j\)列的小格子中的娛樂專案的滿意度,這個滿意度的範圍是\([-1000,1000]\)
Output
輸出檔案中僅一行為一個整數,表示最高的滿意度之和。
注意幾個問題
什麼時候更新答案?
當前格子左邊是\(1\),上邊是\(2\)且除去這個\(1\)和\(2\)後的狀態上沒有插頭。
每次新一行的時候我們會把狀態陣列向右移動兩位,這時候會當\(n\)比較大的時候出現負數,在插入\(Hash\)表取模後需要把\(Ta\)變成正數。
當然也可以有其他的方法,用無符號整型自然溢位或者手動每次\(\&\)一個狀態內全是\(1\),其餘的位置全是\(0\)的數字。實測每次\(\&\)的速度是最快的,大概是其他兩個的\(1/8\)
- 其實寫的漂亮並不會出現負數
- 但是一出現可能掛的很慘哦
在伸出插頭時一定要注意邊界,不能越過\(n\)和\(m\)
Code:
#include <cstdio> #include <cstring> const int N=3e5; const int mod=299987; int n,m,cur,bit[12],ans=-0x3f3f3f3f,a[110][10]; int head[N],to[N],Next[N],cnt[2],tot,dp[2][N],sta[2][N],del; void Ins(int s,int val) { s=s&del; int x=s%mod; for(int i=head[x];i;i=Next[i]) if(sta[cur][to[i]]==s) { dp[cur][to[i]]=dp[cur][to[i]]>val?dp[cur][to[i]]:val; return; } sta[cur][++cnt[cur]]=s; dp[cur][cnt[cur]]=val; to[++tot]=cnt[cur]; Next[tot]=head[x]; head[x]=tot; } void DP() { dp[cur][++cnt[cur]]=0,sta[cur][cnt[cur]]=0; for(int i=1;i<=n;i++) { for(int s=1;s<=cnt[cur];s++) sta[cur][s]=(sta[cur][s]<<2)&(del); for(int j=1;j<=m;j++) { cur^=1; tot=cnt[cur]=0; memset(head,0,sizeof(head)); for(int s=1;s<=cnt[cur^1];s++) { int lassta=sta[cur^1][s],lasans=dp[cur^1][s]; int sr=lassta>>bit[j-1]&3,sd=lassta>>bit[j]&3; if(!sr&&!sd) { Ins(lassta,lasans);//沒選 Ins(lassta|(1<<bit[j-1])|(2<<bit[j]),lasans+a[i][j]);//選 } else if(!sr&&sd) { if(j<m) Ins(lassta,lasans+a[i][j]); if(i<n) Ins((lassta|(sd<<bit[j-1]))&(~(sd<<bit[j])),lasans+a[i][j]); } else if(sr&&!sd) { if(i<n) Ins(lassta,lasans+a[i][j]); if(j<m) Ins((lassta|(sr<<bit[j]))&(~(sr<<bit[j-1])),lasans+a[i][j]); } else if(sr==1&&sd==1) { int ct=1; for(int k=j+2;k<=m;k++) { if((lassta>>bit[k-1]&3)==1) ++ct; if((lassta>>bit[k-1]&3)==2) --ct; if(!ct) { Ins((lassta&(~(sr<<bit[j-1])&(~(sd<<bit[j]))))-(1<<bit[k-1]),lasans+a[i][j]); break; } } } else if(sr==2&&sd==2) { int ct=1; for(int k=j-1;k;k--) { if((lassta>>bit[k-1]&3)==2) ++ct; if((lassta>>bit[k-1]&3)==1) --ct; if(!ct) { Ins((lassta&(~(sr<<bit[j-1])&(~(sd<<bit[j]))))+(1<<bit[k-1]),lasans+a[i][j]); break; } } } else if(sr==2&&sd==1) Ins(lassta&(~(sr<<bit[j-1])&(~(sd<<bit[j]))),lasans+a[i][j]); else if(sr==1&&sd==2&&!(lassta&(~(sr<<bit[j-1]))&(~(sd<<bit[j]))&del)) ans=ans>lasans+a[i][j]?ans:lasans+a[i][j]; } } } } int main() { for(int i=1;i<=10;i++) bit[i]=i<<1; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); del=(1<<(m+1<<1|1))-1; DP(); printf("%d\n",ans); return 0; }
2018.12.20