【UVA11324】 The Largest Clique (Tarjan+topsort/記憶化搜尋)
阿新 • • 發佈:2018-11-07
UVA11324 The Largest Clique
題目描述
給你一張有向圖 \(G\),求一個結點數最大的結點集,使得該結點集中的任意兩個結點 \(u\) 和 \(v\) 滿足:要麼 \(u\) 可以達 \(v\),要麼 \(v\) 可以達 \(u\)(\(u,v\)相互可達也行)。
輸入輸出格式
輸入格式:
第一行:測試資料組數\(T\),每組資料的格式如下:
第一行為結點數 \(n\) 和邊數 \(m\) ,結點編號 \(1~n\)。
以下\(m\)行每行兩個整數 \(u\) 和 \(v\) ,表示一條有向邊 \(u->v\)。
輸出格式:
每組資料輸出最大結點集的結點數
輸入輸出樣例
輸入樣例#1:
1
5 5
1 2
2 3
3 1
4 1
5 2
輸出樣例#1:
4
題解
首先,我們會想到\(Tarjan\)縮點,將縮成的點的\(siz\)大小當做點權。
因為縮完點之後就會是一個\(DAG\),所以可以跑DP。
這種題型有兩種實現方式,\(topsort\)和記憶化搜尋,程式碼中已註明。
轉移就是\(dp[v]=max(dp[v],dp[u]+siz[v])\).
code:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cctype> #include<queue> #define R register #define ll long long #define N 1005 #define M 50005 using namespace std; template<typename T>inline void read(T &a){ char c=getchar();T x=0,f=1; while(!isdigit(c)){if(c=='-')f=-1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();} a=f*x; } int T,n,m,u[M],v[M],ru[N],siz[N],h[N],sta[N],low[N],dfn[N]; int top,num,tot,col[M],vis[N],dp[N],ans,cnt; struct node{ int nex,to; }edge[M]; inline void add(R int u,R int v){ edge[++tot].nex=h[u]; edge[tot].to=v; h[u]=tot; } inline void Tarjan(R int x){ dfn[x]=low[x]=++num; sta[++top]=x;vis[x]=1; for(R int i=h[x];i;i=edge[i].nex){ R int xx=edge[i].to; if(!dfn[xx]){ Tarjan(xx); low[x]=min(low[x],low[xx]); } else if(vis[xx])low[x]=min(low[x],dfn[xx]); } if(dfn[x]==low[x]){ R int now=-1; cnt++; while(now!=x){ now=sta[top]; top--; col[now]=cnt; siz[cnt]++; vis[now]=0; } } } inline void init(){ tot=num=top=ans=cnt=0; memset(h,0,sizeof(h)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(vis,0,sizeof(vis)); memset(siz,0,sizeof(siz)); memset(sta,0,sizeof(sta)); memset(col,0,sizeof(col)); memset(ru,0,sizeof(ru)); memset(dp,-1,sizeof(dp)); } inline void topsort(){ queue<int> q; while(!q.empty())q.pop(); for(R int i=1;i<=cnt;i++) if(!ru[i])q.push(i),dp[i]=siz[i]; while(!q.empty()){ R int x=q.front();q.pop(); for(R int i=h[x];i;i=edge[i].nex){ R int xx=edge[i].to; dp[xx]=max(dp[x]+siz[xx],dp[xx]); --ru[xx]; if(!ru[xx])q.push(xx); } } } inline int search(R int x){ if(dp[x]!=-1)return dp[x]; R int res=siz[x]; for(R int i=h[x];i;i=edge[i].nex){ R int xx=edge[i].to; res=max(search(xx)+siz[x],res); } return dp[x]=res; } int main(){ read(T); while(T--){ read(n);read(m);init(); for(R int i=1;i<=m;i++) read(u[i]),read(v[i]),add(u[i],v[i]); for(R int i=1;i<=n;i++) if(!dfn[i])Tarjan(i); tot=0;memset(h,0,sizeof(h)); for(R int i=1;i<=m;i++) if(col[u[i]]!=col[v[i]]) add(col[u[i]],col[v[i]]),ru[col[v[i]]]++; //記憶化搜尋 for(R int i=1;i<=cnt;i++) ans=max(ans,search(i)); //拓撲排序 topsort(); for(R int i=1;i<=cnt;i++) ans=max(ans,dp[i]); printf("%d\n",ans); } return 0; }