• H-Modify Minieye杯第十五届华中科技大学程序设计邀请赛现场赛


    题面见 https://ac.nowcoder.com/acm/contest/700#question

    题目大意是有n个单词,有k条替换规则(单向替换),每个单词会有一个元音度(单词里元音的个数)和长度,现在希望利用替换规则(每个规则可使用无限次或不用)将每个单词替换成元音度值最小的单词,如果有多个单词元音度同等最小,那么取长度最小的单词。最后输出替换后的n个单词的元音度值之和与长度之和。

    单纯每个点暴力搜,无疑会有爆复杂度的风险 1e5*1e5 ,如果记录搜过的点之后不搜,也会有在一个强连通分量里最早的点能搜到最优解,而后来的点无法get到这个最有解。

    于是我们可以用Tarjan求scc后缩点,然后在缩点之后的分量图开始DFS。因为这个分量图是绝对无环的图,所以可以在不重复搜点下得到最优解。

    比赛时 替换最优解的判断写错了,昏了头把长度的比较搞错。然后此题还有一个坑点,就是开始给的n个单词中可能会有重复,不能直接由string映射至点号。

    比赛时代码修改后的通过版本:

      1 #include<bits/stdc++.h>
      2 
      3 using namespace std;
      4 #define IsVow(i) ((i)=='a'||(i)=='e'||(i)=='i'||(i)=='o'||(i)=='u')
      5 typedef long long ll;
      6 
      7 const int maxn=300000+5;
      8 struct Edge{
      9     int from,to;
     10     int nxt;
     11 };
     12 struct word{
     13     int vow,len;
     14 }voc[maxn], syno[maxn];;
     15 bool vis[maxn];
     16 int head[maxn],tot;
     17 Edge edges[maxn];
     18 map<string , int > dict;
     19 string ori[maxn];
     20 int DFN[maxn],LOW[maxn],STACK[maxn],Belong[maxn];
     21 int scc,dfs_no,top;
     22 bool Instack[maxn];
     23 vector< vector< int > > G(maxn, vector<int>() );
     24 
     25 void addedge(int u,int v){
     26     edges[tot].from=u;
     27     edges[tot].to=v;
     28     edges[tot].nxt=head[u];
     29     head[u]=tot++;
     30 }
     31 
     32 word make_word(string & s){
     33     int cnt=0;
     34     word ans;
     35     ans.len=(int) s.size();
     36     for(auto const& i:s)
     37         if(IsVow(i)) cnt++;
     38     ans.vow=cnt;
     39     return ans;
     40 }
     41 
     42 void Tarjan(int u){
     43     LOW[u]=DFN[u]=++dfs_no;
     44     STACK[++top]=u;
     45     Instack[u]=true;
     46     for(int i=head[u];i!=-1;i=edges[i].nxt){
     47         int v=edges[i].to;
     48         if(!DFN[v]){
     49             Tarjan(v);
     50             LOW[u]=min(LOW[u],LOW[v]);
     51         }
     52         else if(Instack[v])
     53             LOW[u]=min(LOW[u],DFN[v]);
     54     }
     55     if(LOW[u]==DFN[u]){
     56         scc++;
     57         syno[scc]=(word){500005,500005};
     58         while(STACK[top]!=u){
     59             int v=STACK[top];
     60             if(voc[v].vow < syno[scc].vow)
     61             {                      
     62                 syno[scc].vow=voc[v].vow;
     63                 syno[scc].len=voc[v].len;
     64             }
     65             else if( syno[scc].vow == voc[v].vow) 
     66                 syno[scc].len=min(syno[scc].len,voc[v].len);
     67             
     68 
     69             Instack[STACK[top]]=false;
     70             Belong[STACK[top--]]=scc;
     71 
     72         }
     73         Instack[u]=false;
     74         Belong[u]=scc;
     75         top--;
     76                     if(voc[u].vow < syno[scc].vow)
     77             {                      
     78                 syno[scc].vow=voc[u].vow;
     79                 syno[scc].len=voc[u].len;
     80             }
     81             else if( syno[scc].vow == voc[u].vow) 
     82                 syno[scc].len=min(syno[scc].len,voc[u].len);
     83                 }
     84 }
     85 
     86 void DFS(int ind){
     87     //cout<<ind<<":"<<syno[ind].vow<<" , "<<syno[ind].len<<endl;
     88     if(vis[ind]){
     89         return ;
     90     }
     91     vis[ind]=true;
     92 
     93     for(int i=0;i<G[ind].size();++i){
     94         int nxind=G[ind][i];
     95         DFS(nxind);
     96         if(syno[nxind].vow < syno[ind].vow)
     97         {                      
     98             syno[ind].vow=syno[nxind].vow;
     99             syno[ind].len=syno[nxind].len;
    100         }
    101         else if( syno[nxind].vow == syno[ind].vow) 
    102                 syno[ind].len=min(syno[ind].len,syno[nxind].len);
    103         }
    104 }
    105 
    106 int main(){
    107     ios::sync_with_stdio(false);cin.tie(0);
    108     memset(head,-1,sizeof(head));
    109     tot=0;
    110     int n,k;
    111     cin>>n;
    112     int TOT=0;
    113     for(int i=1;i<=n;++i){
    114         string tmp;
    115         cin>>tmp;
    116         ori[i]=tmp;
    117         if(dict.count(tmp)==0){
    118         dict[tmp]=++TOT;
    119         voc[dict[tmp]]=make_word(tmp);
    120         }
    121     }
    122     cin>>k;
    123     //cout<<"N:K:"<<n<<k<<endl;
    124     for(int i=0;i<k;++i){
    125         string frm,to;
    126         cin>>frm>>to;
    127         if(dict.count(frm)==0) {dict[frm]=++TOT;voc[dict[frm]]=make_word(frm);}
    128         if(dict.count(to)==0)  {dict[to]=++TOT;voc[dict[to]]=make_word(to);}
    129         addedge(dict[frm],dict[to]);
    130     }
    131     scc=0;
    132     for(int i=1;i<=n;++i)
    133         if(!DFN[i])
    134             Tarjan(i);
    135     /*
    136     for(int i=1;i<=scc;++i)
    137         syno[i]=(word){500000+5,5000000+5};
    138         */
    139     for(int i=0;i<tot;++i){
    140         int u=edges[i].from,v=edges[i].to;
    141         if(Belong[u]!=Belong[v]){
    142             G[Belong[u]].push_back(Belong[v]);
    143         }
    144     }
    145     
    146     /*
    147     for(int i=1;i<=TOT;++i){
    148         int ind=Belong[i];
    149         if(syno[ind].vow > voc[i].vow)
    150         {
    151             syno[ind].vow= voc[i].vow;
    152             syno[ind].len= voc[i].len;
    153         }
    154         else if(syno[ind].vow == voc[i].len)
    155             syno[ind].len= min(syno[ind].len,voc[i].len); 
    156     }
    157     */
    158     ll X=0,Y=0;
    159     //for(int i=1;i<=scc;++i)
    160     //    cout<<"scc "<<i<<" : "<<syno[i].vow<<" and "<<syno[i].len<<endl;
    161     
    162     for(int i=1;i<=scc;++i){
    163         int ans1,ans2;
    164         ans1=syno[i].vow;
    165         ans2=syno[i].len;
    166         DFS(i);
    167     }
    168     
    169     for(int i=1;i<=n;++i){
    170         int ans1, ans2;
    171         ans1=syno[Belong[dict[ori[i]]]].vow;
    172         ans2=syno[Belong[dict[ori[i]]]].len;
    173         //DFS(Belong[i],ans1,ans2);
    174         //cout<<Belong[i]<<endl;
    175         X+=1ll*ans1;
    176         Y+=1ll*ans2;
    177     }
    178     cout<<X<<' '<<Y<<endl;
    179     return 0;
    180 }
    View Code

    后来看到别人代码,发现可以定义一个类,把优解与劣解的比较重载为<

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 #define IsVow(x) ((x)=='a'||(x)=='e'||(x)=='i'||(x)=='o'||(x)=='u')
      5 typedef long long ll;
      6 const int maxn=3e5+5;
      7 struct word{
      8     ll  vow;
      9     ll  len;
     10     word(){}
     11     word(ll _v,ll _l):vow(_v),len(_l){}
     12     bool operator< (const word & tmp)const{
     13         if(vow==tmp.vow) return len<tmp.len;
     14         return vow<tmp.vow;
     15     }
     16     word operator+ (const word& tmp)const{
     17         return word(vow+tmp.vow,len+tmp.len);
     18     }
     19 };
     20 word voc[maxn],syno[maxn];
     21 
     22 struct Edge{
     23     int from;
     24     int to;
     25     int nxt;
     26 }edges[maxn];
     27 map<string ,int > dict;
     28 string strcash[100000+5];
     29 int head[maxn],tot;
     30 
     31 int DFN[maxn],LOW[maxn],STK[maxn],BLG[maxn],top=0,scc=0,dfs_no=0;
     32 bool InSTK[maxn];
     33 vector< vector< int > > G(maxn+1,vector<int>() );
     34 int vis[maxn];
     35 void Tarjan(int u){
     36     LOW[u]=DFN[u]=++dfs_no;
     37     STK[top++]=u;
     38     InSTK[u]=true;
     39     for(int i=head[u];i!=-1;i=edges[i].nxt){
     40         int v=edges[i].to;
     41         if(!DFN[v]){
     42             Tarjan(v);
     43             LOW[u]=min(LOW[u],LOW[v]);
     44         }
     45         else if(InSTK[v])
     46             LOW[u]=min(LOW[u],DFN[v]);
     47     }
     48     if(DFN[u]==LOW[u]){
     49         int v;
     50         scc++;
     51         syno[scc]=word(500000+5,500000+5);
     52         do{
     53             v=STK[--top];
     54             InSTK[v]=false;
     55             BLG[v]=scc;
     56             if(voc[v]<syno[scc])
     57                 syno[scc]=voc[v];
     58         }while(u!=v);
     59     }
     60 }
     61 
     62 word make_word(string X){
     63     ll _l=1ll*X.length();
     64     ll _v=0;
     65     for(auto const & i:X){
     66         if(IsVow(i)) _v++;
     67     }
     68     return word(_v,_l);
     69 }
     70 
     71 void AddEdge(int u,int v){
     72     edges[tot].from=u;
     73     edges[tot].to=v;
     74     edges[tot].nxt=head[u];
     75     head[u]=tot++;
     76 }
     77 
     78 void DFS(int u){
     79     if(vis[u]) return;
     80     vis[u]=true;
     81     for(auto v:G[u]){
     82         DFS(v);
     83         if(syno[v]<syno[u]) syno[u]=syno[v];
     84     }
     85 }
     86 
     87 int main(){
     88     ios::sync_with_stdio(false);cin.tie(0);
     89     int _n,_k;
     90     int vtx_no=0;
     91     cin>>_n;
     92     for(int i=0;i<_n;++i){
     93         string tmp;cin>>tmp;
     94         strcash[i]=tmp;
     95         if(dict.count(tmp)==0){
     96             dict[tmp]=++vtx_no;
     97             voc[vtx_no]=make_word(tmp);
     98         }
     99     }
    100     cin>>_k;
    101     memset(head,-1,sizeof(head));
    102     tot=0;
    103     for(int i=0;i<_k;++i){
    104         string frm,to;cin>>frm>>to;
    105         if(dict.count(frm)==0){
    106             dict[frm]=++vtx_no;
    107             voc[vtx_no]=make_word(frm);
    108         }
    109         if(dict.count(to)==0){
    110             dict[to]=++vtx_no;
    111             voc[vtx_no]=make_word(to);
    112         }
    113         AddEdge(dict[frm],dict[to]);
    114     }
    115 
    116     top=0,scc=0,dfs_no=0;
    117     for(int i=1;i<=vtx_no;++i){
    118         if(!DFN[i]) Tarjan(i);
    119     }
    120     for(int i=0;i<tot;++i){
    121         int u=edges[i].from,v=edges[i].to;
    122         u=BLG[u];
    123         v=BLG[v];
    124         if(u!=v) G[u].push_back(v);
    125     }
    126     //for(int i=1;i<=vtx_no;++i) cout<<"voc "<<i<<" : "<<voc[i].vow<<" , "<<voc[i].len<<endl;
    127     //for(int i=1;i<=vtx_no;++i) cout<<strcash[i]<<":"<<i<<" belongs to "<<BLG[i]<<endl;
    128     memset(vis,false,sizeof(vis));
    129     //for(int i=1;i<=scc;++i) cout<<syno[i].vow<<" "<<syno[i].len<<endl;
    130     for(int i=1;i<=scc;++i){
    131         DFS(i);
    132     }
    133     //puts("after DFS:");for(int i=1;i<=scc;++i) cout<<syno[i].vow<<" "<<syno[i].len<<endl;
    134     ll __X=0,__Y=0;
    135     for(int i=0;i<_n;++i){
    136         int ob=BLG[dict[strcash[i]]];
    137         __X+=syno[ob].vow;
    138         __Y+=syno[ob].len;
    139     }
    140     cout<<__X<<" "<<__Y<<endl;
    141     return 0;
    142 }
    View Code

    转念一想,所谓点之间的优劣比较不就是先比元音数,元音数同则比长度吗?这不就是 STL里pair 的比较吗!?要啥结构体,要啥重载< !?

    在算导上求scc那部分,有一个定理,有向图G=<V,E>的强连通分量与其逆图~G=<V,~E>的强连通分量是重合的。(逆图,,,沉思,,,

    想一想,如果不缩点,在求解搜点时从每个点搜到其最优解点的路径是一条单向路径,同一个scc内的点能到的最优解是相同的,不同的scc也可能到相同的优解,它们的终点是相同的,终点相同我们可以做逆图!!!也就是从这个解按反向搜到可以到达这个解的所有点。

    在建图时,有向边方向取逆,搜索时从最优的点(用间接排序)开始搜,如此只用一遍DFS。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define IsVow(i) ((i)=='a'||(i)=='e'||(i)=='i'||(i)=='o'||(i)=='u')
     5 typedef long long ll;
     6 
     7 string strcash[100000+5];
     8 
     9 map<string ,int > dict;
    10 pair<ll,ll > word[300000+5];
    11 int word_no=0;
    12 
    13 struct Edge{
    14     int to;
    15     int nxt;
    16 }edges[200000+5];
    17 int head[300000+5],tot;
    18 
    19 int id[300000+5];
    20 bool vis[300000+5];
    21 
    22 pair<ll,ll> make_word(string X){
    23     ll len=X.length();
    24     ll cnt=0;
    25     for(const auto  & i:X){
    26         if(IsVow(i)) cnt++;
    27     }
    28     return make_pair(cnt,len);
    29 }
    30 
    31 void AddVtx(string X){
    32     if(dict.count(X)==0){
    33         dict[X]=++word_no;
    34         word[word_no]=make_word(X);
    35     }
    36 }
    37 
    38 void AddEdge(int u,int v){
    39     edges[tot].to=v;
    40     edges[tot].nxt=head[u];
    41     head[u]=tot++;
    42 }
    43 
    44 bool cmp(int i,int j){
    45     return word[i]<word[j];
    46 }
    47 
    48 void DFS(int u){
    49     if(vis[u]) return;
    50     vis[u]=true;
    51     for(int i=head[u];i!=-1;i=edges[i].nxt){
    52         int v=edges[i].to;
    53         //cout<<u<<"->"<<v<<endl;
    54         if(!vis[v]){
    55             word[v]=word[u];
    56             //cout<<"DFS "<<v<<endl;
    57             DFS(v);
    58         }
    59     }
    60 }
    61 
    62 int main(){
    63     ios::sync_with_stdio(false);cin.tie(0);
    64 
    65     memset(head,-1,sizeof(head));
    66     tot=0;
    67 
    68     int n,k;
    69     cin>>n;
    70     for(int i=0;i<n;++i){
    71         cin>>strcash[i];
    72         AddVtx(strcash[i]);
    73     }
    74     cin>>k;
    75     for(int i=0;i<k;++i){
    76         string f,t;cin>>f>>t;
    77         AddVtx(f);
    78         AddVtx(t);
    79         AddEdge(dict[t],dict[f]);// ~G
    80     }
    81 
    82     for(int i=1;i<=word_no;++i)
    83         id[i]=i;
    84     sort(id+1,id+1+word_no,cmp);
    85     memset(vis,false,sizeof(vis));
    86     for(int i=1;i<=word_no;++i){
    87         DFS(id[i]);
    88     }
    89 
    90     ll X=0,Y=0;
    91     for(int i=0;i<n;++i){
    92         int _no=dict[strcash[i]];
    93         X+=word[_no].first;
    94         Y+=word[_no].second;
    95     }
    96     cout<<X<<" "<<Y<<endl;
    97     return 0;
    98 }
    View Code
  • 相关阅读:
    python复习-数据类型与运算
    爬虫笔记
    网络爬虫-总结
    pymongo使用方法
    Mac下,安装redis之后,启动时遇到的问题
    java实现23种设计模式之迭代器模式
    java实现23种设计模式之观察者模式
    java实现23种设计模式之模版方法模式
    java实现23种设计模式之策略模式
    jvm参数的优化
  • 原文地址:https://www.cnblogs.com/Kiritsugu/p/10770609.html
Copyright © 2020-2023  润新知