題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=5631
解題思路:
這題要求刪除邊,使得無向圖繼續連通。
由於n個節點只有n+1條邊,所以要麼刪除一條邊,要麼刪除兩條邊。
數據量比較小,可以枚舉要刪除的邊即可。
刪除一條邊很簡單,關鍵是怎麼刪除兩條邊。這裏提供一個用圖論的方法解決。
假設我們先枚舉刪除的兩條邊中的一條,那麼要在剩下的圖當中再找一條邊。到底要刪哪一條呢?反正不能是割邊對吧,原因你懂的。
那麼這個問題轉化爲求割邊數量了。。。剩下的邊減去割邊就是可以再刪掉的一條邊。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
const int maxn = 105;
struct Edge
{
int u,v;
}edge[maxn];
int n,ans,sum,map[maxn][maxn];
int dfsn[maxn],Index,low[maxn];
bool cut[maxn][maxn];
void Tarjan(int u,int fa)
{
dfsn[u] = low[u] = ++Index;
for(int i = 1; i <= n; i++)
{
if(map[u][i] == 0 || i == fa) continue;
if(dfsn[i] == 0)
{
Tarjan(i,u);
low[u] = min(low[u],low[i]);
if(low[i] > dfsn[u] && map[u][i] == 1)
cut[u][i] = cut[i][u] = true;
}
else low[u] = min(low[u],dfsn[i]);
}
}
void solve()
{
Index = 0;
memset(dfsn,0,sizeof(dfsn));
memset(cut,false,sizeof(cut));
Tarjan(1,0);
for(int i = 1; i <= n; i++)
if(dfsn[i] == 0) //去掉一條邊後不連通
{
sum--;
return;
}
int cnt = 0; //割邊數量
for(int i = 1; i <= n; i++)
for(int j = i + 1; j <= n; j++)
if(cut[i][j] == true)
cnt++;
ans += n - cnt;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(map,0,sizeof(map));
ans = 0;
sum = n + 1; //sum表示只去掉一條邊的條數
for(int i = 1; i <= n + 1; i++)
{
scanf("%d%d",&edge[i].u,&edge[i].v);
map[edge[i].u][edge[i].v]++;
map[edge[i].v][edge[i].u]++;
}
for(int i = 1; i <= n + 1; i++) //刪除第i條邊
{
map[edge[i].u][edge[i].v]--;
map[edge[i].v][edge[i].u]--;
solve();
map[edge[i].u][edge[i].v]++; //恢復第i條邊
map[edge[i].v][edge[i].u]++;
}
printf("%d\n",ans / 2 + sum);
}
return 0;
}