一、题目链接

http://acm.timus.ru/problem.aspx?space=1&num=1745

二、题意

给定$n$个由'('和')'组成的字符串,每个串最多只能使用$1$次,可以任意改变字符串之间的顺序,要求输出由这些字符串拼接起来可以得到的最大“正规括号序列”的长度,并输出选择方案。

三、思路

首先,这很显然需要$dp$。所以对字符串按照某种规则排序。容易想到的是,把左括号多的放前面,右括号多的放后面,然而,这只是理想的状态,稍微复杂的样例如下:

))()()((
)))((((
()))(((()

对于这些复杂的样例,我们没法想清楚所以情况并逐一对其考虑排序,所以,这个地方留下一个坑,先参考这个博客里的神排序规则。

http://www.cnblogs.com/liulangye/archive/2013/10/02/3349523.html

然后,由于$\sum\limits_{i=1}^{n}|s_i| \le 10000$,$n \le 1000$,所以可以做01背包。

在每一个字符串中,记录它的左括号的个数$lb$和右括号的个数$lb$,同时再记录每个串里面已经匹配的最大长度$num$,并把$lb$和$rb$减去$num$。

$dp[i][j]$表示在前$i$个字符串里面选择若干个字符串且左括号个数比右括号个数exactly多$j$个所能获得的最大正规括号序列长度,那么,最终答案就是$dp[n][0]$。

如果采用“多推一”的$dp$方式,那么有:

  如果$dp[i-1][j] \ne -1$,$dp[i][j]=max(dp[i][j],dp[i-1][j])$,

  如果$dp[i-1][j+ns[i].rb-ns[i].lb] \ne -1$,$dp[i][j]=max(dp[i][j],dp[i-1][j+ns[i].rb-ns[i].lb]+ns[i].num+2*ns[i].rb)$

  其中:$1 \le i \le n,0 \le j \le m$。

如果采用“一推多”的$dp$方式,那么有:

  如果$dp[i][j] \ne -1$,$dp[i+1][j]=max(dp[i+1][j],dp[i][j])$,

  $dp[i+1][j-ns[i].rb+ns[i].lb]=max(dp[i+1][j-ns[i].rb+ns[i].lb],dp[i][j]+ns[i].num+2*ns[i].rb)$,

  其中:$0 \le i < n,0 \le j \le m$。

上式中的$m=\sum\limits_{i=1}^{n}|s_i|$。

要注意的是:

1、在一开始输入的时候,要根据所采用的$dp$姿势来确定下标的起点。

2、从个人感觉来看,第一种"多推一"的$dp$姿势状态转移没那么直观,但是找路径更加直观;第二种"一推多"的$dp$姿势状态转移更加直观,但是找路径没那么直观。

2、无论那种$dp$姿势,无论当前括号序列有没有取,都需要记录父节点。

3、要记录路径,所以在状态转移的时候,无论当前“背包”是选还是不选,都应该设置父节点,否则,肯定会错。

4、由于$dp[i][j]$表示在前$i$个字符串里面选择若干个字符串且左括号个数比右括号个数exactly多$j$个所能获得的最大正规括号序列长度,所以一开始要把$dp$数组初始化为$-1$。在初始状态中,只有$dp[0][0]$是合法的,即$dp[0][0]=0$。

5、在"一推多"的$dp$状态转移代码中,有这么一个判断条件$j-ns[i].rb>=0$,这个条件一定不能写成$j-ns[i].rb+ns[i].lb>=0$,因为题目中说明了,在“正规括号序列”的任意前缀中,左括号的数量都不小于右括号的数量。如果写成了第二种条件,那么“))()((”这种样例也会满足条件。

四、代码

1、“一推多”的$dp$

#include<bits/stdc++.h>
using namespace std;
struct node{
    string s;
    int id,lb,rb,num;
}ns[];

int func(const node& a){
    int t=a.lb-a.rb;
    ?:t/abs(t);
}

bool cmp(const node& a,const node& b){
    int lf=func(a),rf=func(b);
    &&rf==)return a.rb<b.rb;
    &&rf==-)return a.lb>b.lb;
    else return lf>rf;
}

][],ans[],acnt;
][];
int main(){
//    freopen("input.txt","r",stdin);
    ios::sync_with_stdio();
    cin.tie();
    ;
    cin>>n;
    ;i<n;++i){
        cin>>ns[i].s;
        m+=ns[i].s.size();
        ns[i].id=i+;
        ns[i].lb=ns[i].rb=ns[i].num=;
        stack<char> st;
        ;j<ns[i].s.size();++j){
            if(ns[i].s[j]=='(')ns[i].lb++;
            else ns[i].rb++;
            if(ns[i].s[j]=='(')st.push('(');
            ;
        }
        ns[i].lb-=ns[i].num/;
        ns[i].rb-=ns[i].num/;
    }
    sort(ns,ns+n,cmp);
    memset(dp,-,sizeof(dp));
    memset(path,-,sizeof(path));
    dp[][]=;
    ;i<n;++i){
        ;j<=m;++j){
            )continue;
            ][j]<dp[i][j]){
                dp[i+][j]=dp[i][j];
                path[i+][j]=-;
            }
            &&j-ns[i].rb+ns[i].lb<=m
               &&dp[i+][j-ns[i].rb+ns[i].lb]<dp[i][j]+ns[i].num+*ns[i].rb){
                dp[i+][j-ns[i].rb+ns[i].lb]=dp[i][j]+ns[i].num+*ns[i].rb;
                path[i+][j-ns[i].rb+ns[i].lb]=j;
            }
        }
    }
    acnt=;
    ;i>;--i){
        ){
            ans[acnt++]=ns[i-].id;
            j=path[i][j];
        }
    }
    cout<<(dp[n][]==-?:dp[n][])<<" "<<acnt<<endl;
    ;i>=;--i)cout<<ans[i]<<];
    ;
}

2、"多推一"的$dp$

#include<bits/stdc++.h>
using namespace std;
struct node{
    string s;
    int id,lb,rb,num;
}ns[];

int func(const node& a){
    int t=a.lb-a.rb;
    ?:t/abs(t);
}

bool cmp(const node& a,const node& b){
    int lf=func(a),rf=func(b);
    &&rf==)return a.rb<b.rb;
    &&rf==-)return a.lb>b.lb;
    else return lf>rf;
}

][],ans[],acnt;
][];
int main(){
//    freopen("input.txt","r",stdin);
    ios::sync_with_stdio();
    cin.tie();
    ;
    cin>>n;
    ;i<=n;++i){
        cin>>ns[i].s;
        m+=ns[i].s.size();
        ns[i].id=i;
        ns[i].lb=ns[i].rb=ns[i].num=;
        stack<char> st;
        ;j<ns[i].s.size();++j){
            if(ns[i].s[j]=='(')ns[i].lb++;
            else ns[i].rb++;
            if(ns[i].s[j]=='(')st.push('(');
            ;
        }
        ns[i].lb-=ns[i].num/;
        ns[i].rb-=ns[i].num/;
    }
    sort(ns+,ns+n+,cmp);
    memset(dp,-,sizeof(dp));
    memset(path,-,sizeof(path));
    dp[][]=;
    ;i<=n;++i){
        ;j<=m;++j){
            ][j]!=-&&dp[i][j]<dp[i-][j]){
                dp[i][j]=dp[i-][j];
                path[i][j]=-;
            }
            &&j+ns[i].rb-ns[i].lb<=m
               &&dp[i-][j+ns[i].rb-ns[i].lb]!=-
               &&dp[i][j]<dp[i-][j+ns[i].rb-ns[i].lb]+ns[i].num+*ns[i].rb){
                dp[i][j]=dp[i-][j+ns[i].rb-ns[i].lb]+ns[i].num+*ns[i].rb;
                path[i][j]=j+ns[i].rb-ns[i].lb;
            }
        }
    }
    acnt=;
    ;i>;--i){
        ){
            ans[acnt++]=ns[i].id;
            j=path[i][j];
        }
    }
    cout<<(dp[n][]==-?:dp[n][])<<" "<<acnt<<endl;
    ;i>=;--i)cout<<ans[i]<<];
    ;
}

timus1745题解的更多相关文章

  1. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  2. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  5. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  6. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  7. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

随机推荐

  1. 萤石A1互联网报警盒子破解细节分析

    攻击点分析:  萤石A1互联网报警盒子使用“全无线解决方案”,传感器的报警通过433.92MHz射频信号发送给报警主机,报警主机可以通过Wi-Fi联网,将报警上传萤石云端,云端会将信息推送到手机端的“ ...

  2. Android中检测字符编码(GB2312,ASCII,UTF8,UNICODE,TOTAL——ENCODINGS)方法(二)

    Intent intent = getIntent();         String contentUri = null;         Uri uri =null;         if (in ...

  3. ERROR 1045 (28000): Access denied for user 'ODBC'@'localhost' (using password: N O) MYSQL

    ERROR 1045 (28000): Access denied for user ODBC@localhost 刚使用mysql, 碰到这个问题.. C:\Program Files\MySQL\ ...

  4. [C#] 网站程序ASP.NET的性能诊断 - CPU分析

    微软提供了标准的CLR性能分析类库 https://github.com/Microsoft/clrmd 这个类库是开源的代码.能够获取CLR runtime里面几乎所有的信息. 如何获取clrmd编 ...

  5. C#读写基恩士PLC 使用TCP/IP 协议 MC协议

    本文将使用一个Github开源的组件库技术来读写基恩士PLC数据,使用的是基于以太网的TCP/IP实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件支持超级方便的高性能读写操作 g ...

  6. 【error】select timeout问题

    使用摄像头的过程中出现这个问题,说明是找不到摄像头了, 有可能是摄像头驱动问题,也有可能是摄像头接口处接触不良等原因造成的. re 1.select-timeout-opencv; End

  7. Unity3D-常用小功能详解,例子(得分变动效果、倒计时)

    Unity3D-Demo多个功能方法 本文提供全流程,中文翻译.Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) 1 Score Ind ...

  8. L3-017 森森快递 (30 分)

    森森开了一家快递公司,叫森森快递.因为公司刚刚开张,所以业务路线很简单,可以认为是一条直线上的N个城市,这些城市从左到右依次从0到(编号.由于道路限制,第i号城市(,)与第(号城市中间往返的运输货物重 ...

  9. mybatis映射文件mapper.xml的写法(collections...)

    转自:https://blog.csdn.net/two_people/article/details/51759881 在学习mybatis的时候我们通常会在映射文件这样写: <?xml ve ...

  10. (机器学习)小试牛刀 利用Zapier和MonkeyLearn

    MonkeyLearn + Zapier Integration(阅者注:本文介绍如何用Zapier和MonkeyLearn将机器学习实际应用到工作当中,比如:客户咨询和投诉管理,营销邮件管理) We ...