列表

详情


NC20218. [JSOI2015]最小表示

描述

【故事背景】 还记得去年JYY所研究的强连通分量的问题吗?去年的题目里,JYY研究了对于有向图的“加边”问题。对于图论有着强烈兴趣的JYY,今年又琢磨起了“删边”的问题。 
【问题描述】 对于一个N个点(每个点从1到N编号),M条边的有向图,JYY发现,如果从图中删去一些边,那么原图的连通性会发生改变;而也有一些边,删去之后图的连通性并不会发生改变。
JYY想知道,如果想要使得原图任意两点的连通性保持不变,我们最多能删掉多少条边呢? 
为了简化一下大家的工作量,这次JYY保证他给定的有向图一定是一个有向无环图(JYY:大家经过去年的问题,都知道对于给任意有向图的问题,最后都能转化为有向无环图上的问题,所以今年JYY就干脆简化一下大家的工作)。

输入描述

输入一行包含两个正整数N和M。 
接下来M行,每行包含两个1到N之间的正整数xi和yi,表示图中存在一条从xi到yi的有向边。
输入数据保证,任意两点间只会有至多一条边存在。 N ≤ 30,000,M ≤ 100,000

输出描述

输出一行包含一个整数,表示JYY最多可以删掉的边数。

示例1

输入:

5 6
1 2
2 3
3 5
4 5
1 5
1 3

输出:

2

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++ 解法, 执行用时: 284ms, 内存消耗: 220568K, 提交时间: 2021-06-15 21:11:28

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=3e4+5,M=1e5+5; 
struct Edge{int to,nxt;}e[M];
int n,m,fst[N],tote,deg[N],ans;
queue<int>q;
bitset<N>b[N],b2[N];
void adde(int u,int v){e[++tote]=(Edge){v,fst[u]};fst[u]=tote;}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1,u,v;i<=m;i++)scanf("%d%d",&u,&v),adde(u,v),deg[v]++;
	for(int i=1;i<=n;i++){
		b[i][i]=true;
		if(!deg[i])q.push(i);
	}
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=fst[u],v;i;i=e[i].nxt){
			deg[v=e[i].to]--;b2[v]|=(b[v]&b[u]);b[v]|=b[u]; 
			if(!deg[v])q.push(v);
		}
	}
	for(int u=1;u<=n;u++)for(int i=fst[u];i;i=e[i].nxt)if(b2[e[i].to][u])ans++;
	printf("%d\n",ans);
	return 0;
}

上一题