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 }
View Code

 

posted @ 2020-03-29 20:26  古比  阅读(149)  评论(0)    收藏  举报