timus1745题解
Posted 565261641-fzh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了timus1745题解相关的知识,希望对你有一定的参考价值。
一、题目链接
http://acm.timus.ru/problem.aspx?space=1&num=1745
二、题意
给定$n$个由‘(‘和‘)‘组成的字符串,每个串最多只能使用$1$次,可以任意改变字符串之间的顺序,要求输出由这些字符串拼接起来可以得到的最大“正规括号序列”的长度,并输出选择方案。
三、思路
首先,这很显然需要$dp$。所以对字符串按照某种规则排序。容易想到的是,把左括号多的放前面,右括号多的放后面,也就是说,对于每一个字符串,记录它的左括号的个数和右括号的个数。然而,这只是最简单的情况,稍微复杂的样例如下:
))()()((
)))((((
()))(((()
对于这些复杂的样例,我们没法想清楚所以情况并逐一对其考虑排序,所以,这个地方留下一个坑,先参考这个博客里的神排序规则。
http://www.cnblogs.com/liulangye/archive/2013/10/02/3349523.html
然后,由于字符串的长度和不超过$10000$,$n le 1000$,所以可以做01背包。
$dp[i][j]$表示在前$i$个字符串里面选择若干个字符串且左括号个数比右括号个数exactly多$j$个所能获得的最大正规括号序列长度,那么,最终答案就是$dp[n][0]$。
四、细节
五、代码
#include<bits/stdc++.h> using namespace std; struct node{ string s; int id,lb,rb,num; }ns[1010]; int func(const node& a){ int t=a.lb-a.rb; return t==0?0:t/abs(t); } bool cmp(const node& a,const node& b){ int lf=func(a),rf=func(b); if(lf==1&&rf==1)return a.rb<b.rb; else if(lf==-1&&rf==-1)return a.lb>b.lb; else return lf>rf; } int n, dp[1010][10010],ans[1010],acnt; int main(){ // freopen("input.txt","r",stdin); ios::sync_with_stdio(0); cin.tie(0); int m=0; cin>>n; for(int i=0;i<n;++i){ cin>>ns[i].s; m+=ns[i].s.size(); ns[i].id=i+1; ns[i].lb=ns[i].rb=ns[i].num=0; stack<char> st; for(int j=0;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(‘(‘); else if(!st.empty())st.pop(),ns[i].num+=2; } ns[i].lb-=ns[i].num/2; ns[i].rb-=ns[i].num/2; } sort(ns,ns+n,cmp); // for(int i=0;i<n;++i)cout<<ns[i].id<<" "<<ns[i].s<<" "<<ns[i].lb<<" "<<ns[i].rb<<" "<<ns[i].num<<" "<<endl; memset(dp,-1,sizeof(dp)); dp[0][0]=0; for(int i=0;i<n;++i){ for(int j=0;j<=m;++j){ if(dp[i][j]==-1)continue; dp[i+1][j]=max(dp[i+1][j],dp[i][j]); if(j-ns[i].rb>=0&&j-ns[i].rb+ns[i].lb<=m &&dp[i+1][j-ns[i].rb+ns[i].lb]<dp[i][j]+ns[i].num+2*ns[i].rb){ dp[i+1][j-ns[i].rb+ns[i].lb]=dp[i][j]+ns[i].num+2*ns[i].rb; } } } acnt=0; for(int i=n,j=0;i>0;--i){ if(dp[i][j]==dp[i-1][j])continue; else if(j+ns[i-1].rb>=0 &&j+ns[i-1].rb-ns[i-1].lb<=m &&dp[i][j]==dp[i-1][j+ns[i-1].rb-ns[i-1].lb]+ns[i-1].num+2*ns[i-1].rb){ ans[acnt++]=ns[i-1].id; j=j+ns[i-1].rb-ns[i-1].lb; } } cout<<(dp[n][0]==-1?0:dp[n][0])<<" "<<acnt<<endl; for(int i=acnt-1;i>=0;--i)cout<<ans[i]<<" "[i==0]; return 0; }
以上是关于timus1745题解的主要内容,如果未能解决你的问题,请参考以下文章