【UVA11324】 The Largest Clique (Tarjan+topsort/記憶化搜索)


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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM