题目:
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3232
题意:
n*n 的矩阵表示图的连通性,求出至少需要多少条边才能实现连通性。
思路:
根据矩阵建图,Cij = 1则建边(i->j)。题目转化为在原有图的基础上删边,使得连通性相同。
对于一个强连通分量中,n个点则需要n条边,而对于一个树来讲,n个点需要n-1条边。
所以先强连通缩点,变成树,对树进行Floyd。
一开始试图用 并查集代替Floyd,但是并查集是没办法处理有向边的情况!!
AC.
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 205;
const int maxm = 5e4+4;
int g[maxn][maxn];
struct Edge{
int to, next;
}edge[maxm];
int head[maxn], tot;
int low[maxn], dfn[maxn], Stack[maxn], belong[maxn];
int Index, top;
int scc;
bool Instack[maxn];
int num[maxn];
void addedge(int u, int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
void tarjan(int u)
{
int v;
low[u] = dfn[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
for(int i = head[u]; ~i; i = edge[i].next) {
v = edge[i].to;
if(!dfn[v]) {
tarjan(v);
if(low[u] > low[v]) low[u] = low[v];
}
else if(Instack[v] && low[u] > dfn[v]) {
low[u] = dfn[v];
}
}
if(low[u] == dfn[u]) {
scc++;
do {
v = Stack[--top];
Instack[v] = false;
belong[v] = scc;
num[scc]++;
}while(v != u);
}
}
void solve(int N)
{
memset(dfn, 0, sizeof(dfn));
memset(Instack, 0, sizeof(Instack));
memset(num, 0, sizeof(num));
Index = scc = top = 0;
for(int i = 1; i <= N; ++i) {
if(!dfn[i]) tarjan(i);
}
}
void init()
{
tot = 0;
memset(head, -1, sizeof(head));
}
int newg[maxn][maxn];
int main()
{
//freopen("in", "r", stdin);
int n;
while(~scanf("%d", &n)) {
memset(g, 0, sizeof(g));
init();
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= n; ++j) {
scanf("%d", &g[i][j]);
if(i == j) continue;
if(g[i][j] == 1) {
addedge(i, j);
}
}
}
solve(n);
int ans = 0;
for(int i = 1; i <= scc; ++i) {
if(num[i] > 1) ans += num[i];
}
memset(newg, 0, sizeof(newg));
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= n; ++j) {
int u = belong[i], v = belong[j];
if(u != v && g[i][j]) {
newg[u][v] = 1;
}
}
}
for(int k = 1; k <= scc; ++k) {
for(int i = 1; i <= scc; ++i) {
for(int j = 1; j <= scc; ++j) {
if(newg[i][j] && newg[i][k] && newg[k][j]) {
newg[i][j] = 0;
}
}
}
}
for(int i = 1; i <= scc; ++i) {
for(int j = 1; j <= scc; ++j) {
if(newg[i][j] == 1) ans++;
}
}
printf("%d\n", ans);
}
return 0;
}