AtCoder292 E 思维

题意:

给定一副 n ( n ≤ 3000 ) n(n\leq 3000) n(n3000)个顶点, m m m条有向边的图,可以在图中添加有向边,求添加的最少边数,使得这副图满足:如果顶点 a a a到顶点 b b b有边,顶点 b b b c c c右有边,那么顶点 a a a到顶点 c c c也有边

Solution:

考虑一条单向链,按指向的方向按顺序是 A , B , C , D , . . . A,B,C,D,... A,B,C,D,...

显然, A → B , B → C A\rightarrow B,B\rightarrow C AB,BC需要添加一条边 A → C A\rightarrow C AC,此时 A → C , C → D A\rightarrow C,C\rightarrow D AC,CD需要添加 A → D A\rightarrow D AD。更一般的情况是,在从 A A A出发能到达的顶点里,只有与 A A A距离为1的不需要添加边,只需要和其他点建边即可,并查集不适合有向图, O ( n ) O(n) O(n)的搜索可以满足要求,每个顶点搜索一次,总复杂度 O ( n 2 ) O(n^2) O(n2)

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
 
using ll=long long;
const int N=2e5+5,inf=0x3fffffff;
const long long INF=0x3fffffffffffffff,mod=998244353;
 
struct way {
	int to,next;
}edge[N<<1];
int cnt,head[N];
 
void add(int u,int v) {
	edge[++cnt].to=v;
	edge[cnt].next=head[u];
	head[u]=cnt;
}
 
int n,m,dis[N],vis[N];
 
int main() {
	#ifdef stdjudge
		freopen("in.txt","r",stdin);
		auto TimeFlagFirst=clock();
	#endif
 
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
 
	cin>>n>>m;
	for(int i=1;i<=m;i++) {
		int u,v;
		cin>>u>>v;
		add(u,v);
	}
 
	int tot=0;
	queue<int>q;
	for(int i=1;i<=n;i++) {
		for(int j=1;j<=n;j++) vis[j]=false;
		while(!q.empty()) q.pop();
		q.push(i);
 
		while(!q.empty()) {
			int u=q.front(); q.pop();
			vis[u]=true;
			for(int j=head[u];j;j=edge[j].next) {
				int v=edge[j].to;
				if(vis[v]) continue;
				q.push(v);
			}
		}
 
		for(int j=1;j<=n;j++) {
			if(i!=j&&vis[j]) tot++;
		}
		for(int j=head[i];j;j=edge[j].next) tot--;
	}
 
	cout<<tot<<endl;
 
	#ifdef stdjudge
		freopen("CON","r",stdin);
		std::cout<<std::endl<<"耗时:"<<std::clock()-TimeFlagFirst<<"ms"<<std::endl;
		std::cout<<std::flush;
		system("pause");
	#endif
    return 0;
}

你可能感兴趣的:(c++,图论,算法)