la4287(有向图的强连通分量和DAG)

来源:互联网 发布:程序员推荐书单 编辑:程序博客网 时间:2024/06/02 07:30

题意:

给出推到关系,那么问还要几步才能推出所有命题等价

思路:

命题等价就是双连通,所以我们就先求得一共有几个连通分量,然后把每个连通分量看成一个点,就形成了DAG,那么这个DAG需要几条边才能形成强连通

的算法是强连通分量数-(出度与入度的最大值)

代码:

#include<cstdio>#include<stack>#include<iostream>#include<algorithm>#include<cstring>#include<vector>using namespace std;const int maxn = 30000;vector<int> g[maxn];stack<int> s;int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt;int in[maxn], out[maxn];int m, n;void init() {memset(pre, 0, sizeof(pre));memset(lowlink, 0, sizeof(lowlink));memset(sccno, 0, sizeof(sccno));memset(in, 0, sizeof(in));memset(out, 0, sizeof(out));dfs_clock = scc_cnt = 0;for (int i = 0; i < n; i++)              g[i].clear();  }  void dfs(int u) {pre[u] = lowlink[u] = ++dfs_clock;s.push(u);for(int i=0; i<g[u].size(); i++) {int v = g[u][i];if(!pre[v]) {dfs(v);lowlink[u] = min(lowlink[v], lowlink[u]);}else if(!sccno[v]) {lowlink[u] = min(lowlink[u], pre[v]);}}int x;if(pre[u] == lowlink[u]) {scc_cnt++;while(1) {x = s.top();s.pop();sccno[x] = scc_cnt;if(x == u) break;}}}void find_scc() {for(int i=0; i<n; i++) {if(!pre[i]) dfs(i);}}int main() {int kase;int a, b;scanf("%d", &kase);while(kase --) {scanf("%d %d", &n, &m);init();for(int i=0; i<m; i++) {scanf("%d %d", &a, &b);a--;b--;g[a].push_back(b);}find_scc();for(int i=1; i<=scc_cnt; i++) {in[i] = out[i] = 1;//假设5个独立的点}for(int i=0; i<n; i++) {for(int j=0; j<g[i].size(); j++) {int v = g[i][j];if(sccno[i] != sccno[v]) {in[sccno[i]] = out[sccno[v]] = 0;//发现连接就去掉一个度,如果都有出去有进来就行(很迷)}}}int a = 0, b = 0;for(int i=1; i<=scc_cnt; i++) {if(in[i]) a++;if(out[i]) b++;}int ans = max(a,b);if(scc_cnt == 1) ans = 0;printf("%d\n", ans);}return 0;}


0 0
原创粉丝点击