团结就是力量

团结就是力量

https://ac.nowcoder.com/acm/problem/14411

字符串同构,tarjan,hash

题意:

图片说明

分析:

不难想到用tarjan算法,将互相愿意组队的人员划分出来。但是,稍微有困难把你的便是:如何计算这只队伍的团结系数呢?

这里牵扯到了一个知识点:字符串同构!!
对于字符串a,和字符串b我们知道a经过一定的循环就会变成b。我们称a与b同构。
那么倘若我们将a,b都变为其最小的同构字符串c。
然后我们统计又多少人是同构字符串时,直接用hash表统计c的个数不就好了吗?

关键是如何变为最小的同构字符串呢?
这里给出代码:

string getmin(string s) {
    int len = s.size();int i = 0, j = 1, k = 0;
    while(i < len && j < len && k < len) {
        if (s[(i + k) % len] == s[(j + k) % len])k++;
        else if (s[(i + k) % len] > s[(j + k) % len])i = i + k + 1, k = 0;
        else if (s[(i + k) % len < s[(j + k) % len]])j = j + k + 1, k = 0;
        if (i == j)j++;
    }return (s + s).substr(min(i, j), len);
}

简单的说一下:上面又三个指针:i,j,k
分别意味着从i开始的同构字符串,从j开始的同构字符串,k就是个长度。

那么我们在每一个训话中比较的就是s[i+k],s[j+k]
即是以i开始的同构字符串和以j开始的同构字符串比较第k位。
如果第k位相等,那么k++我们比较k+1位

如果s[i+k]>s[j+k]那么我们知道了以i开始的字符串绝对不是最小同构字符串!
但是,同时我们还知道了以i+1,i+2,i+3。。。。。。i+k开始的同构字符串都不是最小字符串!
为什么这样呢?
我们假设从i+h开始,0<=h<=k
那么他一定比j+h的大,因为s[i+k]>s[j+k]啊
对不对,很简单?不难理解的。
然后这时我们就让i=i+k+1,k=0再次开始重新比较吧!

j也一样。当然我如果j==i了j++.否则就不能再比较了。
最后输出min(i,j)为什么是min(i,j)呢?
语言不大好表达,自己思考思考。当然记住也不难

如此,此题得解!!

代码如下:

#include<iostream>
#include<algorithm>
#include<string>
#include<map>
#include<stack>
using namespace std;
const int max_n = 1e5 + 100;
const int max_m = 1e5 + 100;
int n, m;
string ss[max_n];

string getmin(string s) {
    int len = s.size();int i = 0, j = 1, k = 0;
    while(i <= len && j <= len && k <= len) {
        if (s[(i + k) % len] == s[(j + k) % len])k++;
        else if (s[(i + k) % len] > s[(j + k) % len])i = i + k + 1, k = 0;
        else if (s[(i + k) % len < s[(j + k) % len]])j = j + k + 1, k = 0;
        if (i == j)j++;
    }return (s + s).substr(min(i, j), len);
}

struct edge
{
    int to, next;
}E[max_n];
int head[max_n];
int cnt = 1;
void add(int from, int to) {
    E[cnt].to = to;
    E[cnt].next = head[from];
    head[from] = cnt++;
}

int res = 0;
stack<int> st;
int dfn[max_n], low[max_n], color[max_n];
int colour = 0, tot = 0;
map<string, int> mp;
void tarjan(int u) {
    dfn[u] = low[u] = ++tot;st.push(u);
    for (int i = head[u];i;i = E[i].next) {
        int v = E[i].to;
        if (!dfn[v]) { tarjan(v);low[u] = min(low[u], low[v]); }
        else if (color[v] == 0)low[u] = min(low[u], dfn[v]);
    }if (dfn[u] != low[u])return;
    colour++;
    while (st.top() != u) {
        color[st.top()] = colour;
        mp[ss[st.top()]]++;
        st.pop();
    }color[st.top()] = colour;mp[ss[st.top()]]++;st.pop();
    for (auto it = mp.begin();it != mp.end();it++)
        res = max(res, (*it).second);
    mp.clear();
}

void solve() {
    for (int i = 1;i <= n;i++)
        if (!dfn[i])tarjan(i);
    cout << res << endl;
}
void init() {
    fill(head, head + n + 10, false);
    cnt = 1;colour = 0;tot = 0;res = 0;
    fill(dfn, dfn + +n + 10, false);
    fill(color, color + n + 10, 0);
    fill(low, low + n + 10, 0);
}

int main() {
    ios::sync_with_stdio(0);
    while (cin >> n >> m) {
        init();
        for (int i = 1;i <= n;i++) {
            cin >> ss[i];
            ss[i] = getmin(ss[i]);
        }for (int i = 1;i <= m;i++) {
            int u, v;cin >> u >> v;
            add(u, v);
        }solve();
    }
}
全部评论

相关推荐

从输入URL到页面加载发生了什么:总体来说分为以下几个过程:&nbsp;1.DNS解析&nbsp;2.TCP连接&nbsp;3.发送HTTP请求&nbsp;4.服务器处理请求并返回HTTP报文&nbsp;5.浏览器解析渲染页面&nbsp;6.连接结束。简述了一下各个过程的输入输出作用:以下是对从输入&nbsp;URL&nbsp;到页面加载各过程的输入、输出或作用的一句话描述:DNS&nbsp;解析:&nbsp;输入:用户在浏览器地址栏输入的域名(如&nbsp;www.example.com)。输出:对应的&nbsp;IP&nbsp;地址(如&nbsp;192.168.1.1)。作用:将易于记忆的域名转换为计算机能够识别和用于网络通信的&nbsp;IP&nbsp;地址,以便浏览器与目标服务器建立连接。TCP&nbsp;连接:&nbsp;输入:浏览器获得的服务器...
明天不下雨了:参考一下我的说法: 关键要讲出输入网址后涉及的每一个网络协议的工作原理和作用: 涉及到的网络协议: HTTP/HTTPS协议->DNS协议->TCP协议->IP协议->ARP协议 面试参考回答: 第一次访问(本地没有缓存时): 一般我们在浏览器地址栏输入的是一个域名。 浏览器会先解析 URL、解析出域名、资源路径、端口等信息、然后构造 HTTP 请求报文。浏览器新开一个网络线程发起HTTP请求(应用层) 接着进行域名解析、将域名解析为 IP 地址 浏览器会先检查本地缓存(包括浏览器 DNS 缓存、操作系统缓存等)是否已解析过该域名 如果没有、则向本地 DNS 服务器请求解析; 本地服务器查不到会向更上层的 DNS 服务器(根域名服务器->顶级域名服务器->权威域名服务器询问)递归查询 最终返回该域名对应的 IP 地址。(应用层DNS协议)DNS 协议的作用: 将域名转换为 IP 地址。 由于 HTTP 是基于 TCP 传输的、所以在发送 HTTP 请求前、需要进行三次握手、在客户端发送第一次握手的时候、( 浏览器向服务器发送一个SYN(同步)报文、其中包含客户端的初始序列号。TCP头部设置SYN标志位、并指定客户端端口 同时填上目标端口和源端口的信息。源端口是浏览器随机生成的、目标端口要看是 HTTP 还是 HTTPS、如果是 HTTP 默认目标端口是 80、如果是 HTTPS 默认是 443。(传输层) 然后到网络层:涉及到(IP协议) 会将TCP报文封装成IP数据包、添加IP头部,包含源IP地址(浏览器)和目标IP地址(服务器)。IP 协议的作用: 提供无连接的、不可靠的数据包传输服务。 然后到数据链路层、会通过 ARP 协议、获取目标的路由器的 MAC 地址、然后会加上 MAC 头、填上目标 MAC 地址和源 MAC 地址。 然后到物理层之后、直接把数据包、转发给路由器、路由器再通过下一跳、最终找到目标服务器、然后目标服务器收到客户的 SYN 报文后,会响应第二次握手。 当双方都完成三次握手后、如果是 HTTP 协议、客户端就会将 HTTP 请求就会发送给目标服务器。如果是 HTTPS 协议、客户端还要和服务端进行 TLS 四次握手之后、客户端才会将 HTTP 报文发送给目标服务器。 目标服务器收到 HTTP 请求消息后、就返回 HTTP 响应消息、浏览器会对响应消息进行解析渲染、呈现给用户
点赞 评论 收藏
分享
03-29 19:11
门头沟学院 Java
wyp_davis:是可以这样的,不过只要交钱就是假的
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
4
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务