https://www.luogu.com.cn/problem/P1282

题目描述

多米诺骨牌有上下 2 个方块组成,每个方块中有 1~6 个点。现有排成行的

上方块中点数之和记为 S1,下方块中点数之和记为 S2,它们的差为|S1-S2|。例如在图 8-1 中,S1=6+1+1+1=9,S2=1+5+3+2=11,|S1-S2|=2。每个多米诺骨牌可以旋转 180°,使得上下两个方块互换位置。 编程用最少的旋转次数使多米诺骨牌上下 2 行点数之差达到最小。

img

对于图中的例子,只要将最后一个多米诺骨牌旋转180°,可使上下2行点数之差为0。

输入格式

输入文件的第一行是一个正整数n(1≤n≤1000),表示多米诺骨牌数。接下来的n行表示n个多米诺骨牌的点数。每行有两个用空格隔开的正整数,表示多米诺骨牌上下方块中的点数a和b,且1≤a,b≤6。

输出格式

输出文件仅一行,包含一个整数。表示求得的最小旋转次数。

输入输出样例

输入 #1

1
2
3
4
5
4
6 1
1 5
1 3
1 2

输出 #1

1
1

要差值最小,就是填一个 sum/2 的背包…然后每组有且只能必须选择一个加入,转移方程:$d[i][j]=max(d[i-1][j-c_i]+w_i)$

这样只能求得最小差值,题目要求差值最小的情况下旋转次数也最少,所以用 $c[i][j]$ 记录前 i 个骨牌容量为 j 的情况下最少的旋转次数,代价相等的情况下有

$c[i][j]=min(c[i-1][j-c_0],c[i-1][j-c_1] + 1)$

$c_0,c_1$ 表示当前骨牌上下点数。

然后需要注意的是,下标越界… 容量为 0 初始化为 -INF ,即:$d[i][0]=-INF$(调了好久,菜哭

sum 可能是奇数,sum/2 取大的!考虑这样的情况,$pre + c_1 = sum/2 , pre + c_1 = sum/2 + 1$

这样取小的话旋转次数就多 1 。所以取大

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
const int INF=0x3f3f3f3f;
const int MAX=1000+10;
int n,sum=0,d[MAX*6][MAX*6],c[MAX*6][MAX*6],g[MAX][MAX],a[MAX][2],t1,t2;
int main(){
freopen("in","r",stdin);
sf(n);
fi(i,0,n){
sf(a[i][0]);sf(a[i][1]);
sum+=a[i][0]+a[i][1];
}
if(sum&1)
sum/=2,sum++;//如果是奇数,取大的
else sum/=2;
fi(i,0,n){
d[i][0]=-INF;
for(int j=sum;j>=1;j--){
t1= i-1 >= 0?d[i-1][j-a[i][0]] + a[i][0] : a[i][0];
t2= i-1 >= 0?d[i-1][j-a[i][1]] + a[i][1] : a[i][1];
t1= j-a[i][0]>=0?t1:0;
t2= j-a[i][1]>=0?t2:0;
if(t1==t2){
if(c[i-1][j-a[i][0]] <= c[i-1][j-a[i][1]]+1){
d[i][j] =t1;
c[i][j]=c[i-1][j-a[i][0]];
//g[i][j]=1; //记录转移路径
}else {
d[i][j] =t2;
c[i][j]=c[i-1][j-a[i][1]]+1;
//g[i][j]=2;
}
}
else if(t1>t2) {
d[i][j] =t1;
c[i][j]=c[i-1][j-a[i][0]];
//g[i][j]=1;
}else {
d[i][j] =t2;
c[i][j]=c[i-1][j-a[i][1]]+1;
//g[i][j]=2;
}
}
}
//打印方案
// for(int i=n-1;i>=0;i--){
// printf("%-4d",i);
// if(g[i][sum]==1){
// cout<<"1"<<" "<<c[i][sum]<<" "<<a[i][0]<<" "<<sum<<endl;
// sum-=a[i][0];
// }else if(g[i][sum]==2){
// cout<<"2"<<" "<<c[i][sum]<<" "<<a[i][1]<<" "<<sum<<endl;
// sum-=a[i][1];
// }
// }
pf(c[n-1][sum]);
return 0;
}

放一下大佬的解法 P1282 多米诺骨牌 P1282 多米诺骨牌 题解

蒟蒻想不到就是了…