1 条题解

  • 0
    @ 2025-8-24 23:15:39

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Purslane
    AFO

    搬运于2025-08-24 23:15:39,当前版本为作者最后更新于2025-05-20 16:04:10,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    Solution

    初看这道题可能会觉得有些复杂,因为可能会涉及到图的重构相关内容。但是事实上,我们只需要分析所有连通块的大小。

    思考一个简单的问题:如何判断这张图是否连通。

    结论:一个点数 2\ge 2 的图上,至少有 22 个点不是割点。这个结论是容易注意到的,因为考虑圆方树上肯定有至少 22 个叶子对不对。

    也就是说,至少存在两个点,使得删掉点之后图只剩下一个大小为 n1n-1 的连通分量。而显然这个条件是充要的。

    所以如果是连通图,直接返回 nn 即可。

    否则,我们就可以得到最大连通块的大小和数量,以及每个点是否在某一个最大连通块上。把它们全删掉再递归做即可。特别注意判断所有点所在连通块大小都相同的情况。

    但是有一个非常恶心的事情:我们的做法实际上不对 n=2n=2 有效。所以你需要特判。注意如果真的原始 nn 就是 22 那么显然无法确定。

    我们只有确定了所有 3\ge 3 的连通块,且最后只剩下恰好两个点。利用我们确定的第一个连通块中不是割点的某个点删掉后的图中是否有大小为 11 的连通块即可判断。

    时间复杂度:注意到你只会执行 O(n)O(\sqrt n) 次该流程。而每一次的复杂度为 O(n2)O(n^2),所以总复杂度为 O(n2n+nm)O(n^2 \sqrt n + nm),足以通过本题。

    #include<bits/stdc++.h>
    #define ffor(i,a,b) for(int i=(a);i<=(b);i++)
    #define roff(i,a,b) for(int i=(a);i>=(b);i--)
    using namespace std;
    const int MAXN=300+10;
    int n,m,fa[MAXN],sze[MAXN];
    set<int> ok;
    multiset<int> res[MAXN];
    vector<int> ans;
    int find(int k) {return (fa[k]==k)?k:(fa[k]=find(fa[k]));}
    int main() {
    	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    	cin>>n;
    	ffor(i,1,n) {
    		ffor(j,1,n) fa[j]=j,sze[j]=0;
    		cin>>m;
    		ffor(i,1,m) {int u,v;cin>>u>>v,fa[find(v)]=find(u);}
    		ffor(i,1,n) sze[find(i)]++;
    		ffor(j,1,n-1) if(find(j)==j) res[i].insert(sze[j]);
    	}
    	ffor(i,1,n) ok.insert(i);
    	vector<int> fst;
    	while(!ok.empty()) {
    		int al=ok.size();
    		if(al==1) {ans.push_back(1);break ;}
    		int cnt=0;
    		for(auto id:ok) if(*(--res[id].end())==al-1) cnt++;
    		if(cnt>=2) {
    			if(al==2) {
    				int flg=1;
    				for(auto id:fst) flg&=(*(res[id].begin())==1);
    				if(flg) ans.push_back(1),ans.push_back(1);
    				else ans.push_back(2);
    			}
    			else ans.push_back(al);
    			break ;	
    		}
    		pair<int,int> mzx={0,0};
    		for(auto u:ok) {
    			int mx=*(--res[u].end()),cnt=0;
    			for(auto id:res[u]) cnt+=(id==mx);
    			mzx=max(mzx,{mx,cnt});
    		}
    		vector<int> del;
    		for(auto u:ok) {
    			int cnt=0;
    			for(auto id:res[u]) cnt+=(id==mzx.first);
    			if(mzx.second!=cnt) del.push_back(u);
    		}
    		ffor(i,1,mzx.second) ans.push_back(mzx.first);
    		if(del.size()==0) {ans.push_back(mzx.first);break ;}
    		if(fst.empty()) fst=del;	
    		for(auto id:del) ok.erase(id);
    		for(auto id:ok) ffor(i,1,mzx.second) res[id].erase(res[id].find(mzx.first));
    	}
    	
    	sort(ans.begin(),ans.end());
    	cout<<ans.size()<<'\n';
    	for(auto id:ans) cout<<id<<' ';
    	return 0;
    }
    
    • 1

    信息

    ID
    12247
    时间
    1000ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者