【洛谷習題】多米諾骨牌
阿新 • • 發佈:2018-09-08
絕對值最小 gif std sizeof open ide pla int img
題目鏈接:https://www.luogu.org/problemnew/show/P1282
花了好長時間終於寫出了這道題,主要是狀態轉移方程比較奇葩,類似於背包問題,難以想到。
呃呃,寫得DP不多,對於如何想出狀態轉移方程還沒什麽心得,主要是往之前見過的模型上靠。這道題的話,其實可以稍微轉化一下設問,變成有n個數,每次操作可以將其變為相反數,問最少操作幾次可以使總和的絕對值最小。設dp[i][j]為考慮到第i個數,總和為j時最少的操作次數。狀態轉移方程為dp[i][j]=min(dp[i-1][j-num[i]],dp[i-1][j+num[i]]+1)。因為是取最小值,一開始要把dp數組初始化成inf,還要將dp[0][0]初始化成0。反正代碼細節也還是有的。
1 #include<cstdio> 2 #include<cstring> 3 const int maxn=1e3+5,maxm=1e4+5,inf=0x3f3f3f3f; 4 int n,num[maxn],dp[maxn][maxm],mm[maxn],ans; 5 inline int abs(int x) {return x>0?x:-x;} 6 inline int map(int x) {return x+5e3+1;} 7 inline int min(int a,int b) {return a<b?a:b;}AC代碼8 int main() { 9 scanf("%d",&n); 10 int a,b,sum=0; 11 for(int i=1;i<=n;++i) {scanf("%d%d",&a,&b);num[i]=a-b;} 12 memset(dp,inf,sizeof(dp)); 13 for(int i=0;i<=n;++i) {dp[i][map(sum)]=0;sum+=num[i];mm[i]=mm[i-1]+abs(num[i]);} 14 for(int i=1;i<=n;++i) 15for(int j=-mm[i];j<=mm[i];++j) 16 dp[i][map(j)]=min(dp[i-1][map(j-num[i])],dp[i-1][map(j+num[i])]+1); 17 for(int i=0;i<=mm[n];++i) 18 if(dp[n][map(i)]!=inf||dp[n][map(-i)]!=inf) { 19 ans=min(dp[n][map(i)],dp[n][map(-i)]); 20 break; 21 } 22 printf("%d",ans); 23 return 0; 24 }
【洛谷習題】多米諾骨牌