1. 程式人生 > >【洛谷習題】多米諾骨牌

【洛谷習題】多米諾骨牌

絕對值最小 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;}
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) 15
for(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 }
AC代碼

【洛谷習題】多米諾骨牌