• CF467D. Fedor and Essay


    不难看出,这是一道图论的题,只要要求在(r),的个数最小时,(r)的个数与文章长度。

    预备知识

    • STL之map (内置应该是hash之类的)
    • tarjan缩点
    • 树形dp
    • 简单字符串
    • 邻接表存边

    问题分析

    由于同义是单向的,我们建起了单向边,容易的是,如果一个单词可以最后回到他自己,那就把这个环上的点缩成一个scc,记下每个scc的最优(r)和最优(leg)(即(length)但我由于个人原因更喜欢用(lgh))

    在对我们所得的每一个强连通,进行重构图。最后跑一个(dp)即可(可以用深搜实现)

    统计答案时,对每一个word独立操作即可

    如果你还是不太清楚,我们再来看图(样例一)

    我们先建一个对应关系

    然后,我们间的图即为

    然后,我们先进行缩点,然后统计出每个强连通的最优值,最后跑一遍树形dp就可以了

    其实只要看清楚这个题的意思,就很好AC了

    时间复杂度分析

    1. tarjan O(n+m)
    2. 统计最优值 O(n)
    3. 树形dp O(n)

    好的没有毒瘤(n^2) ,此题可过

    附上代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <string>
    #include <map>
    using namespace std;
    const int Maxn=1e5+1;
    map<string,int> wd2;
    int num,n,m,cnt,leg[Maxn],r[Maxn],h[Maxn],vcnt,col[Maxn],dfn[Maxn],low[Maxn],dep,sta[Maxn],top;
    bool fsta[Maxn],flag[Maxn];
    long long ans1,ans2;
    string word[Maxn],str1,str2;
    struct Edge{
    	int fr,to,lac;
    }edge[Maxn];
    struct Node{
    	int rmin,legmin; 
    }scc[Maxn];
    int read(){
    	int x=0;
    	char ch=getchar();
    	while(ch<'0'||ch>'9') ch=getchar();
    	while(ch<='9'&&ch>='0'){
    		x=(x<<1)+(x<<3)+(ch-'0');
    		ch=getchar();
    	}
    	return x;
    }
    char me(char ch){
    	if(ch>='A'&&ch<='Z') ch+=32;
    	return ch;
    }
    void insert(int x,int y){
    	edge[vcnt].fr=x;
    	edge[vcnt].to=y;
    	edge[vcnt].lac=h[x];
    	h[x]=vcnt++;
    }
    string Getstr(){
    	string str;
    	char ch=getchar();
    	while(!((ch>='A'&&ch<='Z')||(ch>='a'&&ch<='z'))){
    		ch=getchar();
    	}
    	while((ch>='A'&&ch<='Z')||(ch>='a'&&ch<='z')){
    		str+=me(ch);
    		ch=getchar();
    	}
    	return str;
    }
    void make(string str){
    	leg[cnt]=str.size();
    	for(int i=0;i<=str.size();i++){
    		if(str[i]=='r') r[cnt]++;
    	}
    	return ;
    }
    void sol(string str){
    	if(wd2[str]==0){
    		wd2[str]=++cnt;
    		make(str);
    	}
    }
    void tarjan(int u){
    	dfn[u]=low[u]=++dep;
    	sta[++top]=u;fsta[u]=1;
    	for(int i=h[u];i!=-1;i=edge[i].lac){
    		int to=edge[i].to;
    		if(dfn[to]){
    			if(fsta[to]) low[u]=min(low[u],dfn[to]);
    			continue;
    		}
    		tarjan(to);
    		low[u]=min(low[u],low[to]);
    	}
    	if(low[u]==dfn[u]){
    		num++;
    		while(fsta[u]){
    			fsta[sta[top]]=0;
    			col[sta[top--]]=num;
    		}
    	}
    	return ;
    }
    void dfs(int u){
    	flag[u]=1;
    	for(int i=h[u];i!=-1;i=edge[i].lac){
    		int to=edge[i].to;
    		if(!flag[to]) dfs(to);
    		if(scc[to].rmin<=scc[u].rmin){
    			if(scc[to].rmin<scc[u].rmin) scc[u].legmin=scc[to].legmin;
    			else scc[u].legmin=min(scc[u].legmin,scc[to].legmin);
    			scc[u].rmin=scc[to].rmin;
    		}
    	}
    	return ;
    }
    int main() {
    // wd1 int-> str 每个str的号->对应str 
    // wd2 str-> int 每个strstr对应 号 
    //	freopen("puditan.in","r",stdin);
    	m=read();
    	for(int i=1;i<=m;i++) {
    		word[i]=Getstr();
    		sol(word[i]);
    	}
    	memset(h,-1,sizeof h);
    	n=read();
    	for(int i=1;i<=n;i++){
    		str1=Getstr(),str2=Getstr();
    		sol(str1);sol(str2);
    		insert(wd2[str1],wd2[str2]);
    	}
    	for(int i=1;i<=cnt;i++)	
    		if(!dfn[i]) 
    			tarjan(i);//cnt指节点个数 
    	for(int i=1;i<=num;i++) scc[i].legmin=0x3f3f3f3f,scc[i].rmin=0x3f3f3f3f;//num是强连通 
    	for(int i=1;i<=cnt;i++)
    		if(scc[col[i]].rmin>=r[i]){
    			if(scc[col[i]].rmin>r[i])  scc[col[i]].legmin=leg[i];
    			else scc[col[i]].legmin=min(scc[col[i]].legmin,leg[i]);
    			scc[col[i]].rmin=r[i];
    		}
    	int q=vcnt;
    	vcnt=0;
    	memset(h,-1,sizeof h);
    	for(int i=0;i<q;i++){
    		int to=edge[i].to,fr=edge[i].fr;
    		if(col[to]==col[fr]) continue;
    		insert(col[fr],col[to]);
    	}
    	for(int i=1;i<=num;i++)	if(!flag[i]) dfs(i);
    	for(int i=1;i<=m;i++){
    		ans1+=scc[col[wd2[word[i]]]].rmin;
    		ans2+=scc[col[wd2[word[i]]]].legmin;
    	}
    	printf("%lld %lld",ans1,ans2);
    	return 0;
    }
    

    感想 ,这道题拖了很久没做,还是内心的惧怕呀

  • 相关阅读:
    大数据集群环境ssh免密码登录设置
    FreeRTOS任务创建删除
    BLE外设设计
    BLE控制器之链路层
    BLE控制器之链路层二
    BLE控制器之物理层特性
    BLE基本理论和概念
    BLE主机之ATT和GATT
    BLE主机之SM层
    BLE主机之L2CAP层
  • 原文地址:https://www.cnblogs.com/zhltao/p/12249805.html
Copyright © 2020-2023  润新知