您的位置:首页 > Web前端 > JavaScript

[JSOI2015]最小表示

2017-08-21 12:48 459 查看

题目大意:
尽可能多地去掉一个有向无环图上的边,使得图的连通性不变。

思路:
拓扑排序,然后倒序求出每个结点到出度为$0$的点的距离$d$,再倒序遍历每一个点$x$,以$d$为关键字对其出边降序排序,尝试加入每一条边,若加边之前两点已经连通,则说明这条边可以删去。可以用bitset维护图的连通性,注意原图是有向图,因此不能用并查集维护。

#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<bitset>
#include<algorithm>
#include<functional>
inline int getint() {
char ch;
while(!isdigit(ch=getchar()));
int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int V=30001;
std::vector<int> e[V];
inline void add_edge(const int u,const int v) {
e[u].push_back(v);
}
int n;
int in[V]={0},top[V]={0};
inline void Kahn() {
std::queue<int> q;
for(int i=1;i<=n;i++) {
if(!in[i]) q.push(i);
}
int cnt=0;
while(!q.empty()) {
int x=q.front();
q.pop();
top[x]=++cnt;
for(unsigned i=0;i<e[x].size();i++) {
int &y=e[x][i];
if(!--in[y]) {
q.push(y);
}
}
}
}
struct Vertex {
int top,id;
bool operator > (const Vertex &another) const {
return top>another.top;
}
};
Vertex v[V];
int dis[V]={0};
int ans=0;
inline bool cmp(const int x,const int y) {
return dis[x]>dis[y];
}
inline void DP() {
for(int i=0;i<n;i++) {
v[i]=(Vertex){top[i+1],i+1};
}
std::sort(&v[0],&v
,std::greater<Vertex>());
for(int i=0;i<n;i++) {
int &x=v[i].id;
for(unsigned j=0;j<e[x].size();j++) {
int &y=e[x][j];
dis[x]=std::max(dis[x],dis[y]+1);
}
}
}
std::bitset<V> bit[V];
inline void cut() {
for(int i=0;i<n;i++) {
int &x=v[i].id;
bit[x].set(x);
std::sort(e[x].begin(),e[x].end(),cmp);
for(unsigned j=0;j<e[x].size();j++) {
int &y=e[x][j];
if(bit[x][y]) ans++;
bit[x]|=bit[y];
}
}
}
int main() {
n=getint();
for(int m=getint();m;m--) {
int u=getint(),v=getint();
add_edge(u,v);
in[v]++;
}
Kahn();
DP();
cut();
printf("%d\n",ans);
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: