[JSOI2015]最小表示
题目大意:
尽可能多地去掉一个有向无环图上的边,使得图的连通性不变。
思路:
拓扑排序,然后倒序求出每个结点到出度为$0$的点的距离$d$,再倒序遍历每一个点$x$,以$d$为关键字对其出边降序排序,尝试加入每一条边,若加边之前两点已经连通,则说明这条边可以删去。可以用bitset维护图的连通性,注意原图是有向图,因此不能用并查集维护。
1 #include<queue> 2 #include<cstdio> 3 #include<cctype> 4 #include<vector> 5 #include<bitset> 6 #include<algorithm> 7 #include<functional> 8 inline int getint() { 9 char ch; 10 while(!isdigit(ch=getchar())); 11 int x=ch^'0'; 12 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 13 return x; 14 } 15 const int V=30001; 16 std::vector<int> e[V]; 17 inline void add_edge(const int u,const int v) { 18 e[u].push_back(v); 19 } 20 int n; 21 int in[V]={0},top[V]={0}; 22 inline void Kahn() { 23 std::queue<int> q; 24 for(int i=1;i<=n;i++) { 25 if(!in[i]) q.push(i); 26 } 27 int cnt=0; 28 while(!q.empty()) { 29 int x=q.front(); 30 q.pop(); 31 top[x]=++cnt; 32 for(unsigned i=0;i<e[x].size();i++) { 33 int &y=e[x][i]; 34 if(!--in[y]) { 35 q.push(y); 36 } 37 } 38 } 39 } 40 struct Vertex { 41 int top,id; 42 bool operator > (const Vertex &another) const { 43 return top>another.top; 44 } 45 }; 46 Vertex v[V]; 47 int dis[V]={0}; 48 int ans=0; 49 inline bool cmp(const int x,const int y) { 50 return dis[x]>dis[y]; 51 } 52 inline void DP() { 53 for(int i=0;i<n;i++) { 54 v[i]=(Vertex){top[i+1],i+1}; 55 } 56 std::sort(&v[0],&v[n],std::greater<Vertex>()); 57 for(int i=0;i<n;i++) { 58 int &x=v[i].id; 59 for(unsigned j=0;j<e[x].size();j++) { 60 int &y=e[x][j]; 61 dis[x]=std::max(dis[x],dis[y]+1); 62 } 63 } 64 } 65 std::bitset<V> bit[V]; 66 inline void cut() { 67 for(int i=0;i<n;i++) { 68 int &x=v[i].id; 69 bit[x].set(x); 70 std::sort(e[x].begin(),e[x].end(),cmp); 71 for(unsigned j=0;j<e[x].size();j++) { 72 int &y=e[x][j]; 73 if(bit[x][y]) ans++; 74 bit[x]|=bit[y]; 75 } 76 } 77 } 78 int main() { 79 n=getint(); 80 for(int m=getint();m;m--) { 81 int u=getint(),v=getint(); 82 add_edge(u,v); 83 in[v]++; 84 } 85 Kahn(); 86 DP(); 87 cut(); 88 printf("%d\n",ans); 89 return 0; 90 }