P1282 多米诺骨牌
(本题解大体思路是对的,但是有差错,因为求得是差值,所以可以装爆,即出现体积50,但是我们装到60的情况,所以要多加这种情况的考虑才能ac)
题意:给出n对多米诺骨牌,让我们求出其差值最小时,翻转次数最小,输出最小次数;
思路:我们可以把最大的都放一遍,剩下一边都是最小的,然后就能得出最大的一个差值
于是要想让这个差值变小,就要翻转,那么翻转某一个得出的值是多少呢 是v[i]*2
那么这个翻转消耗次数可能为1或者-1,为什么呢,因为我们一开始的时候将大的都放一边了
于是我们就得出了一些有价值有重量的物品,现在这个物品有一个容量(最大值放一边后的差值)
我们的任务便是使这个背包尽可能的装满,并且所耗翻转次数最少
于是定义dp【i】【j】,表示放前i个物品,放到j体积时的最少次数
所以我们就按i从小到大枚举 j从小到大枚举即可
最后的答案便是dp【n】【tot~1】第一个有访问过的数,然后输出其翻转次数即可

1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e3+10; 4 int dp[maxn][6005]; 5 bool vs[maxn][6005]; 6 int w[maxn]; 7 int v[maxn]; 8 int main() 9 { 10 11 int n,x,y; 12 int base=0,tot=0; 13 //base表示背包重量,就是初始重量,初始翻转次数 14 scanf("%d",&n); 15 for(int i=1;i<=n;i++) { 16 scanf("%d%d",&x,&y); 17 if(x>y){ 18 v[i]=2*(x-y);//点数变化量看做体积 19 w[i]=1; 20 tot+=x-y; 21 } 22 if(y>x) { 23 v[i]=2*(y-x); 24 w[i]=-1; 25 tot+=y-x; 26 base++;//初始重量 27 } 28 }//用体积为v的物体装总体积为tot的背包,装的体积尽量多的情况下,总重量w最小 背包重量为base 29 for(int i=1;i<=n;i++){ 30 for(int j=1;j<=tot;j++){ 31 dp[i][j]=dp[i-1][j]; 32 vs[i][j]=vs[i-1][j]; 33 if(vs[i-1][j-v[i]]||j-v[i]==0){ 34 if(!vs[i][j]){ 35 dp[i][j]=dp[i-1][j-v[i]]+w[i]; 36 vs[i][j]=1; 37 } 38 else dp[i][j]=min(dp[i][j],dp[i-1][j-v[i]]+w[i]); 39 } 40 } 41 } 42 //printf("%d",base+dp[n][tot]); 43 for(int i=tot;i>=1;i--){ 44 if(vs[n][i]){ 45 printf("%d",base+dp[n][i]); 46 break; 47 } 48 } 49 }