P1212 多米诺骨牌
一开始把所有骨牌设为上大下小,得到一个总差值tot,把它看作背包的总体积。
翻转每个骨牌对答案的影响是上下差值的两倍,把它作为每个物体的体积。
这道题要求用这些物品装到体积最大的情况下,最小的翻转次数。
特别地,我们统计上小下大的个数base作为背包的基础重量。
在进行dp时,选择了一件物品相当于进行一次翻转,如果这个物品原来没有被翻转过,就相当于翻转了一次,因此重量w设为1;如果这个物品之前已经被翻转,即已经被算进了base,因为最终未翻转,需要抵消掉,所以重量w设为-1.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,x,y,base,tot,v[1003],w[1003],dp[1003][1003],vs[1003][1003]; 4 int main(){ 5 cin>>n; 6 for(int i=1;i<=n;i++){ 7 cin>>x>>y; 8 if(x>y){ 9 v[i]=2*(x-y); 10 w[i]=1; 11 tot+=x-y; 12 } 13 if(y>x){ 14 v[i]=2*(y-x); 15 w[i]=-1; 16 tot+=y-x; 17 base++; 18 } 19 } 20 for(int i=1;i<=n;i++) 21 for(int j=1;j<=tot;j++){ 22 dp[i][j]=dp[i-1][j]; 23 vs[i][j]=vs[i-1][j]; 24 if(vs[i-1][j-v[i]]||j-v[i]==0){ 25 if(!vs[i][j]){ 26 dp[i][j]=dp[i-1][j-v[i]]+w[i]; 27 vs[i][j]=1; 28 } 29 else dp[i][j]=min(dp[i][j],dp[i-1][j-v[i]]+w[i]); 30 } 31 } 32 for(int i=tot;i>=1;i--) 33 if(vs[n][i]){ 34 cout<<base+dp[n][i]; 35 return 0; 36 } 37 }