1. 程式人生 > 實用技巧 >團結就是力量(tarjan+字串hash)-牛客

團結就是力量(tarjan+字串hash)-牛客

團結就是力量(tarjan+字串hash)-牛客

題意:給定n個字串,和m對資訊構成圖,字串經過變換後完全相等+兩個點互相連通,可以一起出站,團結力:一起出站的最大人數

解:tarjan求最大連通分量,先將字串預處理為字典序最小(字元串同構最小表示法),最後離散化求最大值(連塊+核對字元)

程式碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
const int mod=142857;
const int inf=0x3f3f3f3f;
typedef long long ll;
typedef pair
<int,int> pii; string getmin(string s) { int len=s.length(); s+=s; int i=0,j=1,k=0,t; while(i<len&&j<len&&k<len) { t=s[(i+k)%len]-s[(j+k)%len]; if(t==0) k++; else { if(t>0) i+=k+1; else j+=k+1
; if(i==j) j++; k=0; } } string res=s.substr(min(i,j),len); return res; } //強連通縮點 int dfn[maxn],low[maxn],tot; int Stack[maxn],vis[maxn],idx; int cnt;//連通分量的個數 int belong[maxn];//記錄每個節點的強連通編號 vector<int> G[maxn*2]; string str[maxn]; int n,m,ans; void tarjan(int
u) { dfn[u]=low[u]=++tot; vis[u]=1; Stack[++idx]=u; for(auto v:G[u]) { if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(vis[v]) { low[u]=min(low[u],dfn[v]); } } if(dfn[u]==low[u]) { cnt++; int k; map<string ,int> mp; do { k=Stack[idx--]; mp[str[k]]++;//對連通分量計數 vis[k]=0; }while(k!=u); for(auto it:mp) ans=max(ans,it.second); } } int main() { while(cin>>n>>m) { for(int i=1; i<=n; i++) G[i].clear(),dfn[i]=low[i]=vis[i]=0; tot=cnt=0; idx=ans=0; for(int i=1; i<=n; i++) { cin>>str[i]; str[i]=getmin(str[i]); //cout<<str[i]<<endl; } for(int i=0; i<m; i++) { int u,v; cin>>u>>v; G[u].push_back(v); } for(int i=1; i<=n; i++) { if(!dfn[i]) tarjan(i); } printf("%d\n",ans); } system("pause"); return 0; }