zoukankan      html  css  js  c++  java
  • 1625

    题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4500

    题目分析:

      本题要将两条路上的车辆混合成一路,混合方法可以是:每次将一个颜色序列中的开头颜色放入新序列的尾部。可以定义状态d[i][j]为第一个序列移走了i辆车,第2个序列移走了j辆车时,新序列的颜色长度。如何进行状态转移呢?

      假设第一个序列为A[n],第二个序列为B[m],C[i][j]表示由A中前i个元素和B中前j个元素组成的最优新序列。下面我们考虑将颜色A[i]加入C[i-1][j]的情况。组成新序列的颜色可以分成两类:(1)已经出现还未结束的颜色 (2)已经结束的颜色 ,设第(1)类元素个数为s,那么将A[i]加入后,每个还未结束的颜色长度均要增加1,所以总长度为 d[i-1][j]+s。 这样我们就得到了状态转移方程 d[i][j]=min{d[i-1][j]+s1,d[i][j-1]+s2} ,s1为将A[i]加入C[i-1][j]的总长度增量,s2为将B[j]加入C[i][j-1]的总长度增量。

      那么主要问题就转换成了如何计算C[i][j]中一景出现还未结束的颜色个数,可以对原先的两个序列预处理一遍,很容易在O(n*m)时间内计算出每个颜色开始和结束的位置。总时间复杂度为O(n*m)。

    代码如下:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 const int maxn=100;//5000;
     6 
     7 int d[maxn+5][maxn+5];
     8 int b[2][26];
     9 int e[2][26];
    10 int L[26];
    11 char s1[maxn+5];
    12 char s2[maxn+5];
    13 int n,m;
    14 void init(){
    15     
    16     memset(L, 0, sizeof L);
    17     memset(b, 0, sizeof b);
    18     memset(e, 0, sizeof e);
    19 }
    20 void pre_process(){
    21     for(int i=0;i<n;i++){
    22         char ch=s1[i];
    23         int id=ch-'A';
    24         if(b[0][id]==0){
    25             b[0][id]=i+1;
    26         }
    27     }
    28     for(int i=n-1;i>=0;i--){
    29         char ch=s1[i];
    30         int id=ch-'A';
    31         if(e[0][id]==0){
    32             e[0][id]=i+1;
    33         }
    34     }
    35     for(int i=0;i<m;i++){
    36         char ch=s2[i];
    37         int id=ch-'A';
    38         if(b[1][id]==0){
    39             b[1][id]=i+1;
    40         }
    41     }
    42     for(int i=m-1;i>=0;i--){
    43         char ch=s2[i];
    44         int id=ch-'A';
    45         if(e[1][id]==0){
    46             e[1][id]=i+1;
    47         }
    48     }
    49 }
    50 int sum(int i,int j,int flag){
    51     int ans=0;
    52     if(flag==0){
    53         for(int k=0;k<26;k++) {
    54             if(((b[0][k]>0&&b[0][k]<=i-1)||(b[1][k]>0&&b[1][k]<=j))&&((e[0][k]>0&&e[0][k]>i-1)||(e[1][k]>0&&e[1][k]>j)))
    55                 ans++;
    56         }
    57     }
    58     else {
    59         for(int k=0;k<26;k++) {
    60             if(((b[0][k]>0&&b[0][k]<=i)||(b[1][k]>0&&b[1][k]<=j-1))&&((e[0][k]>0&&e[0][k]>i)||(e[1][k]>0&&e[1][k]>j-1)))
    61                 ans++;
    62         }
    63     }
    64     return ans;
    65 }
    66 
    67 int main(int argc, const char * argv[]) {
    68     int T;
    69     scanf("%d",&T);
    70     while(T--){
    71         scanf("%s%s",s1,s2);
    72         n=strlen(s1);
    73         m=strlen(s2);
    74         init();
    75         pre_process();
    76         d[0][0]=0;
    77         for(int i=1;i<=n;i++) d[i][0]=d[i-1][0]+sum(i,0,0);
    78         for(int j=1;j<=m;j++) d[0][j]=d[0][j-1]+sum(0,j,1);
    79         for(int i=1;i<=n;i++){
    80             for(int j=1;j<=m;j++){
    81                 d[i][j]=min(d[i-1][j]+sum(i,j,0),d[i][j-1]+sum(i,j,1));
    82             }
    83         }
    84         printf("%d
    ",d[n][m]);
    85     }
    86     return 0;
    87 }
  • 相关阅读:
    in_array()和explode()的使用笔记
    写sql语句连接的时候注意的一个小细节
    在thinkphp框架模板中引用session
    查询数据库所有(某个)表中字段名,数据类型,说明等,导出数据字典
    (委托事件处理)关于多线程执行显示进度条的实例(转)&&线程间操作无效: 从不是创建控件“rtxtEntryNO”的线程访问它。
    判断当前线程所处的状态 (转)以及终止当前线程
    string 字符串的分隔处理与list的相互转换
    C# 动态调用webservice
    C#中的List<string>泛型类示例
    命名空间"system.web"中不存在类型或命名空间名称security"
  • 原文地址:https://www.cnblogs.com/Kiraa/p/5514910.html
Copyright © 2011-2022 走看看