http://acm.timus.ru/problem.aspx?space=1&num=1745
题目大意:
可以是任意的顺序,在满足括号匹配的情况下,求组合成的字符串长度最长
思路:
先将每一个字符串进行处理,处理时将匹配的去掉 比如说 { )(()(())(} 处理后就变成了 {)( (}
当然字符串的长度是没有变化的 处理后的字符串假如说 左括号的个数为L 右括号的个数为R
我们必须确定一个正确的顺序,可以让我们从头到尾的逐个决定是否选用当前字符串,而且不影响最优结果
字符串有 L>R,L<R 和 L=R 三种情况,对于L>R的字符串要放在前面 因为每一个这样的字符串都可以使
左括号 — 右括号 的值变大,
而对于 L<R 的情况对应放在最后,L=R的情况放在中间
对于L<R的字符串之间 需要把 R 小的放在前面, 对于L>R的情况 要用对称思想去确定顺序
确定顺序之后,剩下的就DP就可以了
代码:
#include<iostream> #include<stack> #include<cstdio> #include<queue> #include<cstring> #include<algorithm> #include<vector> #include<set> #include<map> #include<string> #include<cmath> using namespace std; typedef long long ll; typedef pair<int,int> pp; const double eps=1e-9; const int INF=0x3f3f3f3f; const int N=1002; const int M=10002; struct node { string s; int lk,rk; int index; }x[N]; int dp[N][M]; int func(const node& a) { if(a.lk-a.rk>0) return 1; if(a.lk-a.rk<0) return -1; return 0; } bool cmp(const node& a,const node& b) { int lf=func(a),rf=func(b); if(lf==1&&rf==1) return a.rk<b.rk; if(lf==-1&&rf==-1) return a.lk>b.lk; return lf>rf; } int main() { //freopen("data.in","r",stdin); int n; while(cin>>n) { for(int i=0;i<n;++i) { cin>>x[i].s; x[i].index=i+1; stack<char>st; for(unsigned int j=0;j<x[i].s.size();++j) { if(st.empty()||x[i].s[j]=='('||st.top()==')') { st.push(x[i].s[j]); }else { st.pop(); } } x[i].lk=x[i].rk=0; while(!st.empty()) { if(st.top()=='(') ++x[i].lk; else ++x[i].rk; st.pop(); } } sort(x,x+n,cmp); 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) { dp[i+1][j]=max(dp[i+1][j],dp[i][j]); if(j>=x[i].rk) dp[i+1][j-x[i].rk+x[i].lk]=max(dp[i+1][j-x[i].rk+x[i].lk],(int)(dp[i][j]+x[i].s.size())); } } vector<int>vt; int i=n,j=0; while(i>0) { if(dp[i-1][j]==dp[i][j]) i=i-1; else { vt.insert(vt.begin(),i-1); j=j-x[i-1].lk+x[i-1].rk;i=i-1; } } cout<<dp[n][0]<<" "<<vt.size()<<endl; for(unsigned int i=0;i<vt.size();++i) { if(i>0) cout<<" "; cout<<x[vt[i]].index; } cout<<endl; } return 0; }