hdu 4635 强连通缩点
2014-05-06 10:55
253 查看
/* 题意:给出简单有向图的定义:不能有自环,没有重边,不能强连通; 问给出一个初始图,最多加多少条边可以使得这个图满足上述定义。 题解:强连通缩点 首先没有自环,没有重边都十分清晰,然后不能强连通给了一个提示,就是要找出连通分量,那么怎样才能加最多的边 而使得这个图不是强连通,只需保证将这个图分成两个点集,且其中的一个点集到另一点集只能含有单向的边,然后这 两个点集之内的点是强连通,就保证了最优情况的非强连通,由于有一些边是已存在,因此对于加的边的数目来说要最 优的话,必须找出加边最多的情况;然后需要推出加边的公式: ans = N - m - a * b 其中N是指整个图为竞赛图时的总边数,然后已经存在的边为m需要减去,然后就是找出a*b,a,b是指将图分成两个点集 之后两个点集的点的数量,理由:分成两个点集之后,一个点集到另一个点集需要的只有单向边,因此要将所有的反向 边都删除,因为是竞赛图,因此所要去除的边的数目即为a*b,减去之后求出的解就是加边数目,而要使得ans最小,则 a*b最小即可;通过强连通缩点将不可能的点集合成一个点,因为从这些点挑选出的部分点集必然会导致分出的两个点集 有回路,因此强连通分量需要选取所有的点,然后得出的一个缩点后的图就是一个拓扑图,我们要选取的应该是a尽量小 的点集,b=(n-a),那么选一个包含点数目最小的点集就是好了,因此应该选择出度或入度为0的点集,因为如果选择的 是出入度均不为0的点集作为a点集,由于有已存在的边不能删除则必然是存在边返回剩余点集,那样不符合要求,因此 需要选择出入度为0的最小点集。 */ #include <cstdio> #include <cstring> #define clr(a,b) (memset(a,b,sizeof(a))) #define cpy(a,b) (memcpy(a,b,sizeof(a))) const int NV = 100005; const int NE = 100005; inline int Min(int a, int b) {return a < b ? a : b;} inline int Max(int a, int b) {return a > b ? a : b;} int deep, scc, top, SZ, n; struct edge {int v, next;} E[NE]; int head[NV], dfn[NV], low[NV], id[NV], st[NV]; int indegree[NV],outdegree[NV]; int mindegree[NV],moutdegree[NV]; int sum[NV]; bool in[NV]; inline void init(int _n) { n = _n; clr(head, -1); clr(dfn, -1); clr(in,false); deep = scc = SZ = top = 0; } void tarjan(int u) { int v, i; dfn[u] = low[u] = ++ deep; st[top++] = u; in[u] = true; for (i = head[u]; i != -1; i = E[i].next) { v = E[i].v; if (dfn[v] == -1) { tarjan(v); low[u] = Min(low[u], low[v]); } else if (in[v]) { low[u] = Min(low[u], dfn[v]); } } if (low[u] == dfn[u]) { int tsum = 0; do { tsum ++; v = st[--top]; in[v] = false; id[v] = scc; // 缩点 } while (u != v); sum[scc] = tsum; scc ++; } } inline void insert(int u, int v) { E[SZ].v = v; E[SZ].next = head[u]; head[u] = SZ ++; } inline void solve() { for (int i = 1; i <= n; i++) { if (dfn[i] == -1) { tarjan(i); } } } int main(void) { int t,n,m; scanf("%d",&t); for(int cas = 1; cas <= t; cas++) { scanf("%d%d",&n,&m); init(n); clr(indegree,0); clr(outdegree,0); clr(sum,0); for(int i=0; i<m; i++) { int u,v; scanf("%d%d",&u,&v); insert(u,v); } solve(); if (scc == 1) { printf("Case %d: -1\n",cas); continue; } for(int i=1; i<=n; i++) { for (int j = head[i]; j != -1; j = E[j].next) { if (id[i] != id[E[j].v]) outdegree[id[i]]++,indegree[id[E[j].v]]++; } } int tans = n*n; for(int i=0; i<scc; i++) if (indegree[i] == 0 || outdegree[i] == 0) tans = Min(tans, sum[i]*(n-sum[i])); printf("Case %d: %d\n",cas,n*(n-1)-m-tans); } return 0; }
相关文章推荐
- hdu 4635 Strongly connected 强连通缩点
- hdu 4635 (强连通缩点)
- hdu 4635 强连通缩点
- hdu 4635 Strongly connected (强连通缩点)
- hdu 4635 Strongly connected 强连通缩点
- HDU 4635 多校第四场 1004 强联通
- hdu 5934(强连通缩点)
- hdu 4635(强连通+缩点)
- HDU 4635 多校四-1004
- HDU 4635
- HDU 4635 Strongly connected(强连通分量,变形)
- HDU 4635 Strongly connected (Tarjan+一点数学分析)
- hdu Proving Equivalences (强连通缩点)
- HDU 4635 Strongly connected(强连通分量)
- hdu-4635(有向图缩点+判断强连通)
- hdu 4635 Strongly connected(强连通+缩点)
- HDU 4635 Strongly connected (2013多校4 1004 有向图的强连通分量)
- 多校第四场 Hdu 4635 强连通分量
- hdu 4635 Strongly connected (tarjan强连通分量)
- hdu 4635 Strongly connected 强连通