Bzoj4484 [Jsoi2015]最小表示
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 103 Solved: 65
Description
【故事背景】
还记得去年JYY所研究的强连通分量的问题吗?去年的题目里,JYY研究了对于有向图的“加边”问题。对于图论有着强烈兴趣的JYY,今年又琢磨起了“删边”的问题。
【问题描述】
对于一个N个点(每个点从1到N编号),M条边的有向图,JYY发现,如果从图中删去一些边,那么原图的连通性会发生改变;而也有一些边,删去之后图的连通性并不会发生改变。
JYY想知道,如果想要使得原图任意两点的连通性保持不变,我们最多能删掉多少条边呢?
为了简化一下大家的工作量,这次JYY保证他给定的有向图一定是一个有向无环图(JYY:大家经过去年的问题,都知道对于给任意有向图的问题,最后都能转化为有向无环图上的问题,所以今年JYY就干脆简化一下大家的工作)。
Input
输入一行包含两个正整数N和M。
接下来M行,每行包含两个1到N之间的正整数x_i和y_i,表示图中存在一条从x_i到y_i的有向边。
输入数据保证,任意两点间只会有至多一条边存在。
N<=30,000,M<=100,000
Output
输出一行包含一个整数,表示JYY最多可以删掉的边数。
Sample Input
5 6
1 2
2 3
3 5
4 5
1 5
1 3
1 2
2 3
3 5
4 5
1 5
1 3
Sample Output
2
HINT
Source
图论 拓扑排序 bitset
将有向图拓扑排序,易知每条有向边只会从拓扑序小的点连向拓扑序大的点。
按照拓扑序倒序处理每一个点,将当前点指向的所有点按拓扑序从小到大排序,贪心加边,若当前目标点已经被连通,就不需要加这条边。
用bitset维护连通性十分方便。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cmath> 5 #include<cstring> 6 #include<bitset> 7 using namespace std; 8 const int mxn=100010; 9 int read(){ 10 int x=0,f=1;char ch=getchar(); 11 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 13 return x*f; 14 } 15 struct edge{ 16 int v,nxt; 17 }e[mxn<<1]; 18 int hd[mxn],mct=0; 19 void add_edge(int u,int v){ 20 e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;return; 21 } 22 int q[mxn],hed,tl; 23 int ind[mxn],id[mxn]; 24 int n,m; 25 void topo(){ 26 hed=1;tl=0; 27 for(int i=1;i<=n;i++)if(!ind[i])q[++tl]=i; 28 while(hed<=tl){ 29 int u=q[hed];hed++; 30 for(int i=hd[u];i;i=e[i].nxt){ 31 int v=e[i].v; 32 --ind[v]; 33 if(!ind[v]){q[++tl]=v;} 34 } 35 } 36 for(int i=1;i<=tl;i++)id[q[i]]=i; 37 return; 38 } 39 int cmp(int a,int b){ 40 return id[a]<id[b]; 41 } 42 bitset<30010>b[30010]; 43 int st[mxn],top=0; 44 int ans=0; 45 void solve(){ 46 int i,j; 47 for(i=tl;i;i--){ 48 int u=q[i]; 49 b[u][u]=1;top=0; 50 for(int j=hd[u];j;j=e[j].nxt) 51 st[++top]=e[j].v; 52 sort(st+1,st+top+1,cmp); 53 for(int j=1;j<=top;j++){ 54 if(b[u][st[j]])ans++; 55 else b[u]|=b[st[j]]; 56 } 57 } 58 printf("%d\n",ans); 59 return; 60 } 61 int main(){ 62 // freopen("in.txt","r",stdin); 63 int i,j,u,v; 64 n=read();m=read(); 65 for(i=1;i<=m;i++){ 66 u=read();v=read(); 67 add_edge(u,v); 68 ++ind[v]; 69 } 70 topo(); 71 solve(); 72 return 0; 73 }
本文为博主原创文章,转载请注明出处。