Gym 101081K Pope's work

题目链接:Gym - 101081K

题意:给n个箱子,每个箱子有一个重量W和一个承重R,表示它上面能放最多R-W的重量。问最多能把多少箱子堆到一堆。

思路:发现在一堆箱子里,两个箱子交换位置,对其他所有箱子没有影响。

所以我们先构造偏序关系,考虑两个箱子i和j,假设Ri<Rj。

那么我们发现假如Ri >= Wi + Wj,则Rj >= Wi + Wj。换言之,假如i上面可以放j,则j上面一定可以放j。但反之不一定成立。

所以可以认为i<=j,按照这种偏序关系排序。

按这种关系排序的好处在于,对于某个排在i后面的箱子j,假如我们想把j放在i上面,则这种情况显然不如把i放在j上面的情况好。

换言之,对于每个箱子,我们只需要考虑排在它前面的箱子即可。

接下来,用d[i][j]表示用前i个箱子堆j个箱子的最小重量。d[i][j]为INF时表示用前i个箱子不能堆j个箱子。

那么可以得到转移方程

最终答案为使d[n][i]不为INF的最大的i。

代码如下:

 1 #include"cstdio"
 2 #include"iostream"
 3 #include"cstring"
 4 #include"algorithm"
 5 #include"cstdlib"
 6 #include"vector"
 7 #include"set"
 8 #include"map"
 9 #include"cmath"
10 using namespace std;
11 typedef long long LL;
12 const LL MAXN=1010;
13 const LL MOD=1000000000+7;
14 const LL INF=0x3f3f3f3f;
15 
16 struct Box
17 {
18     int w,r;
19     bool operator < (const Box x)
20     {
21         return r<x.r;
22     }
23 };
24 Box s[MAXN];
25 int d[MAXN][MAXN];
26 int main()
27 {
28 #ifdef LOCAL
29     freopen("in.txt","r",stdin);
30     // freopen("out.txt","w",stdout);
31 #endif
32     int t;
33     scanf("%d",&t);
34     for(int tt=1;tt<=t;tt++)
35     {
36         int n;
37         scanf("%d",&n);
38         for(int i=1;i<=n;i++)
39             scanf("%d%d",&s[i].w,&s[i].r);
40         sort(s+1,s+1+n);
41         memset(d,INF,sizeof(d));
42         for(int i=0;i<=n;i++)
43             d[i][0]=0;
44         for(int i=1;i<=n;i++)
45             for(int j=1;j<=i;j++)
46             {
47                 d[i][j]=d[i-1][j];
48                 if(d[i-1][j-1]+s[i].w <= s[i].r && d[i-1][j-1]+s[i].w < d[i][j])
49                     d[i][j]=d[i-1][j-1]+s[i].w;
50             }
51         for(int i=n;i>=0;i--)
52             if(d[n][i]<INF)
53             {
54                 printf("%d
",i);
55                 break;
56             }
57     }
58     return 0;
59 }
原文地址:https://www.cnblogs.com/zarth/p/6757472.html