多米诺骨牌题解

题目描述

多米诺骨牌有上下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行点数之差达到最小。

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

输入格式:

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

输出格式:

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

输入样例#1:

4

6 1

1 5

1 3

1 2

输出样例#1:

1

【题解】

将复杂的问题简化了,根据题目要求,就是要求最小的翻转步数使得所有骰子的上下差之和最小

这样的描述很像是背包问题的描述:在给定容量的背包内放最大价值的物品。

唯一的差别就在于最小与给定,但这不影响做题

有了表层的理解我们不难仿造出类似背包且是01背包问题的状态转移方程

\(f(i,j)=\max\{f(i-1,j),f(i-1,j-2*(b[i]-a[i])\}\)

条件为\((j-2*(b[i]-a[i])\ge 0)\)初始条件为\(f[1][tot]=0\),tot为初始状态上下所有差之和

代表的意义是 前i个使得上下差之和为j的最小步数**

关于\((j-2*(b[i]-a[i])\ge 0)\)可以很简单地推导出来:

初始是\(a-b\)

那么翻转之后为\(b-a\)

那么两者相差\((b-a)-(a-b)=2*(b-a)\)

证毕

所以代码以简单地写出来:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
int n,a[1010],b[1010],f[2][15000],tot=0,sum=0;

int main() {
    memset(f,inf,sizeof(f));
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
        scanf("%d%d",&a[i],&b[i]),tot+=a[i]-b[i],sum+=abs(a[i]-b[i]);
    f[1][sum+tot]=0;
    tot=sum;
    tot<<=1;
    int t=0;
    for(int i=1; i<=n; i++,t^=1) {
        for(int j=0; j<=tot; j++) {
            f[t][j]=min(f[t][j],f[t^1][j]);
            if(j-2*(b[i]-a[i])>=0&&j-2*(b[i]-a[i])<=tot)
                f[t][j]=min(f[t][j],f[t^1][j-2*(b[i]-a[i])]+1);
        }
    }
    tot>>=1;
    for(int i=0; i<=tot; i++) {
        int k=min(f[t^1][tot-i],f[t^1][tot+i]);
        if(k!=inf) {
            printf("%d\n",k);
            break;
        }
    }
    return 0;
}

这是调试的代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
int n,a[1010],b[1010],f[2][15000],tot=0,sum=0;

int main() {
    memset(f,inf,sizeof(f));
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
        scanf("%d%d",&a[i],&b[i]),tot+=a[i]-b[i],sum+=abs(a[i]-b[i]);
    //printf("%d %d\n", sum, tot);
//  printf("%d %d\n",sum,tot);
    /*f[1][sum-(b[1]-a[1])*2]=1,*/f[1][sum+tot]=0;
    tot=sum;
    tot<<=1;
    int t=0;
//  puts("-------");
    for(int i=1; i<=n; i++,t^=1) {
        for(int j=0; j<=tot; j++) {
            f[t][j]=min(f[t][j],f[t^1][j]);
            if(j-2*(b[i]-a[i])>=0&&j-2*(b[i]-a[i])<=tot)
                f[t][j]=min(f[t][j],f[t^1][j-2*(b[i]-a[i])]+1);
        //  if(j+2*(b[i]-a[i])>=0&&j+2*(b[i]-a[i])<=tot)f[t][j+2*(b[i]-a[i])]=min(f[t][j+2*(b[i]-a[i])],f[t^1][j]+1); //翻
        //  if(j+2*(b[i]-a[i])>=0&&j+2*(b[i]-a[i])<=tot)printf("(%d,%d) ",j,j+2*(b[i]-a[i]));
        //  if(f[t][j]==inf)printf("inf ");
    //      else
        //  printf("%3d ",f[t][j]);
        }
    //  puts("");
    }
//  puts("-------");
    tot>>=1;
    for(int i=0; i<=tot; i++) {
        int k=min(f[t^1][tot-i],f[t^1][tot+i]);
        if(k!=inf) {
            printf("%d\n",k);
            break;
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/kcfzyhq/p/8475495.html

时间: 2024-11-02 14:45:43

多米诺骨牌题解的相关文章

poj 1717==洛谷P1282 多米诺骨牌

Dominoes Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6571   Accepted: 2178 Description A domino is a flat, thumbsized tile, the face of which is divided into two squares, each left blank or bearing from one to six dots. There is a ro

ZOJ 3650(多米诺骨牌 dp + 线段树优化)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3650 题意: 给你n个骨牌,每个骨牌有一个在x轴上的位置和高度,每个骨牌可以想左推也可以向右推,问最少多少步可以把骨牌全部推倒. 思路: 之前Goodbye 2014 上的E题就是一道多米诺骨牌的题目,虽然跟这道题目不太一样但是还是提供了一下思路, 附题解的链接: http://blog.csdn.net/u013649253/article/details/4

P1282 多米诺骨牌

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行点数之差达到最小. 对于图中的例子,只要将最后一个多米诺骨牌旋转180°,可使上下2行点数之差为0. 输入输出格式 输入格式:

POJ 1135 Domino Effect(最短路 多米诺骨牌)

题意 题目描述: 你知道多米诺骨牌除了用来玩多米诺骨牌游戏外,还有其他用途吗?多米诺骨牌游戏:取一 些多米诺骨牌,竖着排成连续的一行,两张骨牌之间只有很短的空隙.如果排列得很好,当你推 倒第 1张骨牌,会使其他骨牌连续地倒下(这就是短语"多米诺效应"的由来). 然而当骨牌数量很少时,这种玩法就没多大意思了,所以一些人在 80 年代早期开创了另一个 极端的多米诺骨牌游戏:用上百万张不同颜色.不同材料的骨牌拼成一幅复杂的图案.他们开创 了一种流行的艺术.在这种骨牌游戏中,通常有多行骨牌同时

洛谷 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行点数之差达到最小. 对于图中的例子,只要将最后一个多米诺骨牌旋转180°,可使上下2行点数之差为0. 输入输出格式 输入格式: 输入文件的第一行是一个正

luogu 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行点数之差达到最小. 对于图中的例子,只要将最后一个多米诺骨牌旋转180°,可使上下2行点数之差为0. 输入输出格式 输入格式: 输入文件的第一行是一个正

FZU 2163 多米诺骨牌

Problem Description Vasya很喜欢排多米诺骨牌.他已经厌倦了普通的多米诺骨牌,所以他用不同高度的多米诺骨牌.他从左边到右边,把n个多米诺骨牌沿一个轴放在桌子上.每一个多米诺骨牌垂直于该轴,使该轴穿过其底部的中心.第i个多米诺骨牌具有坐标xi与高度hi.现在Vasya想要知道,对于每一个多米诺骨牌如果他推倒的话,右侧会有多少个多米诺骨牌也会倒下. 想想看,一个多米诺倒下,如果它严格的触动右侧的多米诺骨牌,被触碰的也会倒下.换句话说,如果多米诺骨牌(初始坐标x和高度h)倒下,会

S6 edge+的多米诺骨牌效应:大屏的趋势

日前,为庆祝三星S6 edge+国行版的顺利发售,三星盖乐世社区的一些粉丝自发组织了三星疯狂"盖星人"第一期活动--活动现场除了可以对S6 edge+进行全方面体验之外,还将演示著名的多米诺骨牌游戏.作为一个对手机产品有着持续关注和体验热情的"用户"来说,这样的活动自然不能错过,于是在通过三星盖乐世社区的规则报名之后,笔者顺利通过审核,之后终于迎来了到现场体验的日期. 这次的疯狂"盖星人"线下活动主要有两个内容环节,分别是三星S6 edge+的产

状态压缩动态规划 -- 多米诺骨牌

用1*2 的骨牌通过组合拼成 m * n 的大矩形,问有几种拼法. 题目链接:http://poj.org/problem?id=2411 状态转移: 1.由于上一行的该列竖直放置骨牌为 0,影响到当前行的该列,当前行的该列为 1 2.当前行骨牌横放,上一行骨牌横放, 都为11 3.上一行该列置为 1,当前行当前列立着放为 0 #include <iostream> #include <cstring> using namespace std; #define MAXSIZE 12