20170814(三道题-DAG上DP 二分查找 map)

题目

NYOJ_16 矩形嵌套

题意

有n个矩形,每个矩形可以用a,b来描述,表示长和宽。矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a

解决

DAG上的动态规划
1. 二元关系能够用图来建立模型
2. 用A到B有单向边来表示矩形A能嵌套在矩形B中
3. 一个矩形不能嵌套自己,也就是说没有自环现象,也就是一个DAG

const int maxn = 1005;
struct rec
{
    int a,b;
    bool operator<(rec r2)const
    {
        if(a<r2.a&&b<r2.b) return true;     //重载小于号表示可以嵌套
        return false;
    }
}R[maxn];

vector<int> G[maxn];            //用于保存单向边
int dp[maxn];
int maxx,n;
int dfs(int u)
{
    int &ans=dp[u];
    if(ans>0) return ans;
    ans=1;
    for(int i=0;i<G[u].size();i++){
        ans=max(ans,dfs(G[u][i])+1);
    }
    maxx=max(maxx,ans);
    return ans;
}
int main()
{
    int cases,a,b;
    //open();
    scanf("%d",&cases);
    while(cases--)
    {
        scanf("%d",&n);
        memset(dp,0,sizeof(dp));
        rep(i,0,n) G[i].clear();

        rep(i,0,n){
            scanf("%d%d",&a,&b);
            if(a<b) swap(a,b);
            R[i].a=a;R[i].b=b;
        }
        rep(u,0,n) rep(v,0,n) if(R[u]<R[v]) G[u].push_back(v);  //添加边

        maxx=0;
        rep(i,0,n) dfs(i);
        printf("%d\n",maxx);
    }
}

GYM_100253

Travelling Camera Problem

题意

背景是记者和摄影师,摄影师的位置可以在C[]数组上(升序排好),(很难描述啊,直接看题目吧)记者的位置只能在X[]上(固定序),摄影师和记者的距离不能超过r,问摄影师最少要走过的距离

解决

暴力扫应该会超时吧…
1. 根据求出dist=sqrt(r*r-1.0);
2. 如果当前位置可以拍摄到,不用动
3. 把每一个X位置映射到C数轴上,加减dist后就能得到下一个目标位置在C轴对应的区间左端点和区间右端点
4. 对区间左端点做lower_bound,对区间右端点做upper_bound

int m,n,r;
double now,sum,tg;
double dist,C[300005],X[300005];
int get1(double x)
{
    int left;
    x-=dist;
    left=lower_bound(C,C+m,x)-C;        //lower_bound获取第一个>=x的地址
    if(left!=m) return left;
    return -1;
}
int get2(double x)
{
    int right;
    x+=dist;
    right=upper_bound(C,C+m,x)-C;       //upper_bound获取第一个严格>x的地址,减一则表示<=x的最后一个位置
    if(right!=m&&right!=0) return right-1;
    return -1;
}
int main()
{
    //open();
    scanf("%d%d%d",&m,&n,&r);
    rep(i,0,m) scanf("%lf",&C[i]);
    rep(i,0,n) scanf("%lf",&X[i]);

    dist=sqrt(r*r-1.0);
    //de(dist);
    now=C[0];
    sum=0;

    for(int i=0;i<n;i++)
    {
        tg=X[i];
        //de(now);
        //de(tg);
        if(fabs(now-tg)<=dist) {continue;}  //当前位置可以拍摄到目标位置
        double l,r;
        int left=get1(X[i]);
        if(left==-1){l=INF;}
        else l=fabs(C[left]-now);

        int right=get2(X[i]);
        if(right==-1){r=INF;}
        else r=fabs(C[right]-now);

        if(l<=r)
        {
            sum+=l;
            now=C[left];
            //de(left);
        }
        else
        {
            sum+=r;
            now=C[right];
            //de(right);
        }

    }
    printf("%.6lf\n",sum);
    //这个题我坑了,lower_bound和upper_bound用反了,也是因为不怎么熟悉吧,该打
}

GYM_100443

题意

每一天给出一些单词,对于每次询问,输出7天内出现次数最多的N个词(当最后一个单词出现次数一致的时候,可以>=N)

解决

方案1:

这个题在怎么排序上面纠结…
1. 用map保存最近七天单词出现的次数
2. 同样用set保存七天内单词出现的次数,类型为pair<int,string>,优先第一关键字升序排序,我们想拿到降序,把出现的次数变成负的扔进去就好了.

pair类型
1. 本身是一个结构体,优先第一关键字升序排序
2. make_pair()无需写出型别,就可以生成一个pair对象.比如我们不用写pair

#define mp make_pair
#define rep(i,a,b) for(int i=a;i<(b);++i)

vector<string> day[maxn];
map<string,int> map7;                           //map建立str到int的映射
set<pair<int,string> > set7;                    //set实现排序

int main()
{
    //freopen("data.txt","r",stdin);
    int days=0;
    string str;
    while(cin>>str)
    {
        if(str=="<text>"){days++;continue;}
        if(str=="</text>")
        {
            if(days>7)
            {
                rep(i,0,sz(day[days-7])){
                    string &s=day[days-7][i];
                    int cnt=map7[s];
                    map7[s]--;
                    set7.erase(set7.find(mp(-cnt,s)));  //注意set的erase方法参数是迭代器,而find函数返回值也是一个迭代器
                    set7.insert(mp(-(cnt-1),s));
                }
                day[days-7].clear();                    //清空7天前的数据防止爆内存
            }
            continue;
        }
        if(str=="<top")
        {
            int n,cnt=0,last=1e9;
            cin>>n;
            printf("<top %d>\n",n);
            set<pair<int,string> >::iterator it;        //it迭代器不能进行加减操作...
            for(it=set7.begin();it!=set7.end();it++)
            {
                if(it->first==0) break;
                if(it->first!=last&&cnt>=n) break;
                cout<< it->second <<' '<< -(it->first) <<endl;
                cnt++;
                last=it->first;
            }
            puts("</top>");
            continue;

        }
        if(str.size()<4) continue;
        day[days].push_back(str);
        if(map7.count(str))
        {
            int cnt=map7[str];
            set7.erase(set7.find(mp(-cnt,str)));
            set7.insert(mp(-(cnt+1),str));
            map7[str]++;
        }
        else
        {
            map7[str]=1;
            set7.insert(mp(-1,str));                        //把负数扔进去是为了按照绝对值降序,最后拿到最大值
        }
    }
    return 0;
}
方案2:
struct node
{
    int num;
    string str;
    node(){}
    node(int n,string s){num=n;str=s;}
    bool operator<(const node &n2)const
    {
        if(num==n2.num) return str<n2.str;
        return num>n2.num;
    }
};
vector<string> day[maxn];
map<string,int> map7;                           //map建立str到int的映射
set<node> set7;                                 //set实现排序

int main()
{
    //freopen("data.txt","r",stdin);
    int days=0;
    string str;
    while(cin>>str)
    {
        if(str=="<text>"){days++;continue;}
        if(str=="</text>")
        {
            if(days>7)
            {
                rep(i,0,sz(day[days-7])){
                    string &s=day[days-7][i];
                    int cnt=map7[s];
                    map7[s]--;
                    set7.erase(node(cnt,s));            //注意set的erase方法参数是迭代器,而find函数返回值也是一个迭代器
                    set7.insert(node(cnt-1,s));
                }
                day[days-7].clear();                    //清空7天前的数据防止爆内存
            }
            continue;
        }
        if(str=="<top")
        {
            int n,cnt=0,last=1e9;
            cin>>n;
            printf("<top %d>\n",n);
            set<node>::iterator it;                     //it迭代器不能进行加减操作...
            for(it=set7.begin();it!=set7.end();it++)
            {
                if(it->num==0) break;
                if(it->num!=last&&cnt>=n) break;
                cout<< it->str <<' '<< it->num <<endl;
                cnt++;
                last=it->num;
            }
            puts("</top>");
            continue;

        }
        if(str.size()<4) continue;
        day[days].push_back(str);
        if(map7.count(str))
        {
            int cnt=map7[str];
            set7.erase(set7.find(node(cnt,str)));
            set7.insert(node(cnt+1,str));
            map7[str]++;
        }
        else
        {
            map7[str]=1;
            set7.insert(node(1,str));
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值