[题解]P8186 [USACO22FEB] Redistributing Gifts S

P8186 [USACO22FEB] Redistributing Gifts S

对于每行的初始礼物,将它和左侧的礼物连单向边。

最后,每个点都可以通过交换获得所在强连通分量上的任意一个礼物,而其他礼物则无法获得。

image

可以用 Floyd 跑传递闭包(即判断有向图中两点是否连通)。时间复杂度 \(O(n^3)\)\(O(\dfrac{n^3}{\omega})\)bitset 优化)。

也可以用 Tarjan 跑一遍强连通。时间复杂度 \(O(n^2)\)

Floyd 979ms
#include<bits/stdc++.h>
#define eb emplace_back
using namespace std;
const int N=502;
int n,a[N][N],d[N][N];
vector<int> G[N];
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++) cin>>a[i][j];
		for(int j=1;j<=n;j++){
			if(a[i][j]==i) break;
			d[i][a[i][j]]=1;
			G[i].eb(a[i][j]);//先记录出边
		}
	}
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				d[i][j]|=d[i][k]&&d[k][j];
			}
		}
	}
	for(int i=1,flg;i<=n;i++){
		flg=0;
		for(int j:G[i]){
			if(d[j][i]){//若出边能回来 说明有环
				cout<<j<<"\n";
				flg=1;
				break;
			}
		}
		if(!flg) cout<<i<<"\n";
	}
	return 0;
}
Floyd bitset 301ms
#include<bits/stdc++.h>
#define eb emplace_back
using namespace std;
const int N=502;
int n,a[N][N];
bitset<N> d[N];
vector<int> G[N];
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++) cin>>a[i][j];
		for(int j=1;j<=n;j++){
			if(a[i][j]==i) break;
			d[i][a[i][j]]=1;
			G[i].eb(a[i][j]);//先记录出边
		}
	}
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			if(d[i][k]) d[i]|=d[k];
		}
	}
	for(int i=1,flg;i<=n;i++){
		flg=0;
		for(int j:G[i]){
			if(d[j][i]){//若出边能回来 说明有环
				cout<<j<<"\n";
				flg=1;
				break;
			}
		}
		if(!flg) cout<<i<<"\n";
	}
	return 0;
}
Tarjan 292ms
#include<bits/stdc++.h>
#define eb emplace_back
using namespace std;
const int N=502;
int n,a[N][N],dfn[N],low[N],tim,c[N],idx;
vector<int> G[N];
stack<int> st;
bitset<N> vis;
inline void tarjan(int x){
	low[x]=dfn[x]=++tim;
	st.push(x),vis[x]=1;
	for(int i:G[x]){
		if(!dfn[i]) tarjan(i),low[x]=min(low[x],low[i]);
		else if(vis[i]) low[x]=min(low[x],dfn[i]);
	}
	if(dfn[x]==low[x]){
		++idx;
		while(1){
			int t=st.top();
			st.pop(),vis[t]=0,c[t]=idx;
			if(t==x) break;
		}
	}
}
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++) cin>>a[i][j];
		for(int j=1;j<=n;j++){
			if(a[i][j]==i) break;
			G[i].eb(a[i][j]);
		}
	}
	for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(c[a[i][j]]==c[i]){
				cout<<a[i][j]<<"\n";
				break;
			}
		}
	}
	return 0;
}
posted @ 2025-10-31 08:01  Sinktank  阅读(6)  评论(0)    收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2025 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.