小6有一副多米诺骨牌,它们的高度不一,且不计厚度。
小6将这些骨牌从左到右排成一排立起来,如果向左或者向右推倒其中一个骨牌,那么它碰到左边或者右边的骨牌会一起连续倒下。
也就是说,每个骨牌只能向左或者向右倒下。
小6想知道,最少需要直接推倒多少骨牌,才能把所有的骨牌全都放倒。
第一行是一个整数T,表示数据组数。(T≤20)
每组输入中的第一行为多米诺骨牌数量N(1≤N≤100),
接着有N行,第i行有两个正整数Pi、Hi分别代表多米诺骨牌的横坐标和该骨牌的高度,数据保证每个坐标最多只有一个骨牌,并且所给出的Pi是递增的。
(1≤Pi, Hi≤1000)
对于每组输入,在一行中输出一个整数,表示要把所有骨牌直接或间接放倒最少需要直接推倒的骨牌数量。
#include
#include
#include
#include
#include
#include
using namespace __gnu_pbds;
using namespace std;
#define INF 0x3f3f3f3f
#define PB push_back
#define MP make_pair
#define REP(X,N) for(int X=0;X=L;X--)
#define CLR(A,X) memset(A,X,sizeof(A))
#define IT iterator
#define RIT reverse_iterator
typedef long long LL;
typedef unsigned long long uLL;
typedef pair PII;
typedef vector VI;
typedef vector VII;
#define PQ std::priority_queue
#define HEAP __gnu_pbds::priority_queue
#define X first
#define Y second
#define lson l,m,o<<1
#define rson m+1,r,o<<1|1
/********************************
************头文件***************
********************************/
int p[110];
int h[110];
int dp[110];
int main() {
ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
CLR(dp,INF);
REP(i, n) cin >> p[i] >> h[i];
dp[0] = 0;
REP(i, n) {
//首先从左向右倒
int r = p[i] + 1;//要确保在跟自己进行比较的时候一定会把自己推到
//这里要注明下面的p[x]表示第x+1块多米诺牌,dp[x]表示第x块多米诺牌最少第几次被推倒
REP2(j, i, n-1) {
if (p[j] < r) {//说明可以推到;p[j]和下面的dp[j+1]指的是一块牌
dp[j+1] = min(dp[j+1], dp[i]+1);
//这里应用的很巧妙,当i==j是必然是可以进入循环的
//如果dp[j+1]没有被更新过,说明以前不会被推倒,它被推倒的次数最小值就会比上一张牌多一,
//但是如果被更新过,说明上一张牌可以把这一张砸到,那么dp[i]==dp[j+1],所以最小值仍为dp[j+1]
//当j>i的时候要进入循环必然是能被砸到的,这时候dp[j+1]肯定应该等于dp[j]
//这里很难想明白,可以把下面这句话输出来,很有助于理解
//cout<<'1'<<" "<
#include
using namespace std;
#define INF 0x3f3f3f3f
const int maxn = 110;
int p[maxn];
int h[maxn];
int dp[maxn];
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
memset(dp,INF,sizeof(dp));
/**记录节点从 1开始,思考更方便(统一dp和p,h的索引)*/
for(int i = 1;i<=n;i++) cin>>p[i]>>h[i];
/**初始化dp[0]是为dp[1]服务*/
dp[0] = 0;
for(int i = 1;i<=n;i++){
/*r和l的作用是不一样的,向左和向右的思路是不一样的。因为向右为正序,更新后的r
为向右推倒的最大位置。向左为逆序,l表示当前要被推到的位置。所以在向右的时候else
要break,因为再进行下去已经没有意义了。而向左则不一样,即使位置较大的p也可能推到当前的位置。
这样就有一个弊端,dp[i]并不一定为推到i的最小次数(好像也没什么卵用)不用管**/
int r = p[i]+h[i];
for(int j = i;j<=n;j++){
if(p[j]