多米诺……差点就倒这了
发布于 2018-09-03 21:00 4023 次浏览 3 赞 来自 笔试面试  

在多米诺这题上耽误了很长时间,一开始以为样例给错了,后来画图才想明白。两个细节,1、输入的第一个并不代表位置是第一块;2、题里说范围内所有的骨牌都会倒,所以不能只纠结挨着的骨牌,隔着其他牌被碰倒也是有可能的。因为只能倒向x轴正方向,所以先对位置考虑,然后倒序dp就行了。

25 条回复

难受,我最后也是这样写的,不够时间调了

2018-09-03 21:03

考虑了呀,还是只通过59多

import sys
N=int(sys.stdin.readline().strip())
S=[]
for i in range(N):
    S+=[map(int,sys.stdin.readline().strip().split(' '))]
from operator import itemgetter
S1=sorted(S,key=itemgetter(0))
# print S1
num=[1 for i in range(N)]
for i in range(N-2,-1,-1):
    latter=N-1-i
    T=[]
    for k in range(1,latter+1):
        if S1[i][1]>S1[i+k][0]-S1[i][0]:
            # print i
            # print num
            T+=[k-1+num[i+k]]
            # print num
    if T==[]:
        1
    else:
        num[i]=max(T)+1
    # print T

# print num
snum=[1 for i in range(N)]
for i in range(N):
    ind=S.index(S1[i])
    snum[ind]=num[i]
ssnum=map(str,snum)
print ' '.join(ssnum)


2018-09-03 21:04

嚓,恍然大悟,还以为是样例给错了

2018-09-03 21:04

卧槽。。第二点蒙蔽了 唉还以为题目给错样例了

2018-09-03 21:04

我去,我也认为的是样例给错了

2018-09-03 21:04

样例也不给个特殊的,我想了半天没想明白。。。

2018-09-03 21:05

这个题有问题吧 他是按[x+1,x+h]算的

2018-09-03 21:05

难受,我是后面才想到应该用dp,之前其他方法只ac了55%,凉凉

2018-09-03 21:05

我用排序方法做的,过了50%,但是不知道错在哪里

1. 按照 x 排序
2. 按照 x 从大到小的顺序计算能倒下的骨牌的个数
3. 按照原始的输入顺序排序
4. 输出骨牌的个数
2018-09-03 21:06
coder_Y5S67QCQ 回复 coder_M4FmCRrl

这也太坑了吧

2018-09-03 21:07

我用超级笨的方法解,远程编译报错是什么情况。请各位大侠指教。

#include<iostream>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;

class pos{
public:
    int first;
    int second;
    pos(int a, int b){
        first = a;
        second = b;
    }
    friend bool operator < (pos& a, pos& b);
};
bool operator < (pos& a, pos& b){
    return a.first < b.first;
}
int main(){
    int n, a, b;
    cin >>n;
    if(n<=0) return 0;
    vector<pos> data;
    map<int, int> order;
    for(int i=0; i<n; i++){
        cin >> a>> b;
        data.emplace_back(pos(a,b));
        order[a] = i;
    }
    sort(data.begin(), data.end());

    vector<int> record(n, 1);
    data.back().second=-1;
    for(int i=n-2; i>=0; i--){
        int cnt=1;
        int j = i+1;
        int last=-1;
        while(j<n){
            int tmp = data[j].first - data[i].first;
            int jump=1;
            if(data[i].second > tmp){
                if(data[j].second != -1){
                    jump = data[j].second+1;
                    cnt += record[j];
                }
                else{
                    cnt += 1;
                }
                last = j;
            }
            j += jump;
        }
        if(cnt==1)
            data[i].second = -1;
        else if(last != -1)
            data[i].second = last;
        record[i] = cnt;
    }
    vector<int> res(n,0);
    for(int i=0; i<n; i++){
        int p = data[i].first;
        int ord = order[p];
        res[ord] = record[i];
    }
    cout<<res[0];
    for(int i=1; i<n; i++)
        cout<<' '<<res[i];
    return 0;
}


2018-09-03 21:07

求楼主的AC代码啊,死活找不着错...

2018-09-03 21:07
coder_sVAvpe24 回复 coder_M4FmCRrl

不是,确实是[x+1,x+h-1],(10,10)的按这个公式能推到3个(包括自己),然后,推到的(16,5)还能推到最后一个,所以一共是4个

2018-09-03 21:11
coder_DDG35HYm 回复 coder_MAYTAGC7

莫不是选了java编译环境吧,默认是Java的

2018-09-03 21:12
coder_7UNZ2H69 回复 coder_sVAvpe24

正解

2018-09-03 21:12

 恍然大悟

2018-09-03 21:15
coder_n5TpasSB 回复 coder_Y5S67QCQ

按照原始输入顺序排序你是怎么做的呢?我也是这个做法就是错错错。。

2018-09-03 21:17

求解求解

2018-09-03 21:19
coder_6RVF6CVP 回复 coder_n5TpasSB

你在输入里面给它一个参数来表示它读入时的下标,最后再按照这个下标重新排序不就行了。可惜!55%超时

2018-09-03 21:24
coder_M4FmCRrl 回复 coder_sVAvpe24

他说的高度都不相同 应该是x不同吧 样例里面都有一样的

2018-09-03 22:19

我的,刚刚没写出来,大家帮忙看看

if __name__ == '__main__':
# n = int(input())
# dic = {}
# seq = {}
# nums = {}
# for i in range(n):
#     tmp = input().strip().split()
#     x = int(tmp[0])
#     h = int(tmp[1])
#     dic[x] = h
#     nums[x] = 1#初始情况,内个坐标能推到自己
# dic = sorted(dic.items(),key=lambda x:x[0])

n = 4
dic = {16: 5, 20: 5, 10: 10, 18: 2}
nums = {k:1 for k,v in dic.items()}
dic = sorted(dic.items(),key=lambda x:x[0])
# print(dic)
#dic= [(10, 10), (16, 5), (18, 2), (20, 5)]
"""
    [x+1,x+h-1]

    坐标           能推倒的x范围 valid_range
    [(10, 10),  -> [11,19]
    (16, 5),    ->[17,20]
    (18, 2),    ->[19,19]
    (20, 5)]    ->[21,26]
    
    
    
    """
#从右向左统计, nums[x]=numbers 是坐标为x时,
#他能推到的右边的多米诺的数量(包含自己,注意:这里计算的不会递归推到)
for i in range(n-1,-1,-1):
nowCor = dic[i]
this_x = nowCor[0]
this_h = nowCor[1]
for j in range(i-1,-1,-1):
preCor = dic[j]
pre_x = preCor[0]
pre_h = preCor[1]
valid_range  = range(pre_x+1,pre_x+pre_h)#[x+1,x+h-1]
if this_x in valid_range:
nums[pre_x] += 1
# print(nums)
#统计完以后nums为 {16: 3, 20: 1, 10: 3, 18: 1},x为16的最多推到三个,自己、一个18、一个20

"""
    dic = [(10, 10), (16, 5), (18, 2), (20, 5)]
    从左向右开始统计,比如坐标为(10,10)时,
    查找nums[10]=3,说明除了自己以外,往后还能推到2个,
    也就是(16,5)和(18,2)
    则遍历这两个,看看能不能递归推到其他的坐标
      (16,5)时,查表nums[16]=3,
        则发现下标为16的能推到3个,而下标为10的能推到16,故有4个,比10自己能推倒的多,所以更新nums[10]=4
    依次类推
    """

for i in range(n):
now_x = dic[i][0]
times = nums[now_x]
for j in range(i+1,times):
next_x = dic[j][0]
next_time = nums[next_x]
nums[now_x] = max(nums[now_x],nums[next_x]+1)
# print(nums)
rs = list(nums.values())
for i in rs:
print(i,'',end="")
print()


2018-09-03 22:24

public static void main(String[] args) {

Scanner sc=new Scanner(System.in);

int n=Integer.parseInt(sc.nextLine());

Map<Integer, Integer> map1=new HashMap<Integer, Integer>();

int[] array=new int[n];    //存储x轴数值

for(int i=0;i<n;i++){

String s=sc.nextLine();

String[] ss=s.split(" ");

map1.put(Integer.parseInt(ss[0]), Integer.parseInt(ss[1]));

array[i]=Integer.parseInt(ss[0]);

}

find(map1,array);

}


private static void find(Map<Integer, Integer> map1, int[] array) {

// TODO Auto-generated method stub

for(int i=0;i<array.length;i++){

int min=array[i]+1;

int max=array[i]+map1.get(array[i])-1;

int num=1;

for(int j=0;j<array.length;j++){

if(array[j]>=min && array[j]<=max){

num++;

int max1=array[j]+map1.get(array[j])-1;

if(max1>max)

max=max1;

}

}

System.out.print(num+" ");

}

}


2018-09-04 01:26
coder_4Z7UNWKQ 回复 coder_C5mCI8Mk

测试用例换一下顺序就不对了,比如说把16 5那个放在最后一行输入

2018-09-04 11:11

考虑到了这两点,看不出哪里错了,跪求帮忙看一下,java语言。

思路:先count所有在【x+1,x+h-1】范围内的牌数,再找到这个范围内最后一个牌,再count被这个牌压倒的牌数


public void duo() {

Scanner scan=new Scanner(System.in);

int n=scan.nextInt();

int[][] arr=new int[n][3];

for(int i=0;i<n;i++) {

arr[i][0]=i;

arr[i][1]=scan.nextInt();

arr[i][2]=scan.nextInt();

}

int fall=0;

int index=0;

int temph=0;

for(int i=0;i<n;i++) {

int temp=0;

int count = 1;

fall=arr[i][2]+arr[i][1]-1;

for(int j=0;j<n;j++) {

if(arr[j][1]>arr[i][1]&arr[j][1]<=fall) {

count++;

if(temp<arr[j][1]) {

temp= arr[j][1];

index=j;

}

}

}

temph=arr[index][1]+arr[index][2]-1;

System.out.println(arr[index][1]+","+arr[index][2]);

  for(int k=0;k<n;k++) {

  if(arr[k][1]>fall&&arr[k][1]<=temph) {

count++;

}

}

System.out.print(count+" ");

}

}


2018-09-04 17:00

你dp是n^2还是O(n), 我dpO(n^2) 优化到O(nlogn) 挂了 求dp递推式

2018-09-04 22:42
添加回复
回到顶部