原题链接:点击打开链接
题目大意为:
给你一个n (n<=200 000)点,m (m<=1000 000)条边的无向图(无向图含重边)。
询问在图中添加一条边后,能够使得新图中的桥最少。
在无向图中的任意一条路径上,如果路径中含有桥,我们只要连接路径的两个端点,就可以将路径中的桥取缔。
因此,题目变为在图中找一条含有桥的数量最多的路径。
算法设计:
利用塔尖算法标记出无向图中的所有桥。
把图中所有的桥设置权值为1,非桥的边权值为0。
此时,在途中给找出一条权值最大的路径。
看网上的题解,说可以建立一颗包涵所有桥的树,然后求树的直径。但我的方法并没有建立树,而是直接在原有的图像图中,利用Heap+Bfs(类似于Heap+Dijkstra)找出的最长链。
而在题目中,由于数据比较大,会发生栈溢出,因此要添加语句:
#pragma comment(linker,"/STACK:102400000,1024000")
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<map>
#include<stack>
#pragma comment(linker,"/STACK:102400000,1024000")
using namespace std;
const int inf=999999999;
const int maxn=200005;
struct Edge{
int from, to;
int dist;
Edge (){};
Edge (int a,int b):from(a),to(b),dist(0){}
};
vector<Edge>edges;
vector<int>G[maxn];
int cnt_bridge;
void add(int a,int b){
Edge e(a,b);
edges.push_back(e);
e.from=b;e.to=a;
edges.push_back(e);
int mm=edges.size();
G[a].push_back(mm-2);
G[b].push_back(mm-1);
}
int pre[maxn];
bool iscut[maxn];
int dfs_clock;
int low[maxn];
class Cuts_Bridges{
public:
int n;
void init(int n){
this->n=n;
for(int i=1;i<=n;i++)G[i].clear();
edges.clear();
memset(iscut,0,sizeof(iscut));
memset(pre,0,sizeof(pre));
dfs_clock=0;
cnt_bridge=0;
}
int dfs(int u,int fa,int lastEdge){
int lowu=pre[u]=++dfs_clock;
int child=0;
for(int i=0;i<G[u].size();i++){
Edge &e=edges[G[u][i]];
int v=e.to;
if(!pre[v]){
child++;
int lowv=dfs(v,u,G[u][i]);
lowu=min(lowv,lowu);
if(lowv>=pre[u]){
iscut[u]=true;
if(lowv>pre[u]){
e.dist=edges[G[u][i]^1].dist=1;
cnt_bridge++;
}
}
}
else if(pre[v]<pre[u]&&lastEdge!=(G[u][i]^1))
lowu=min(lowu,pre[v]);
}
if(fa<0&&child==1)iscut[u]=0;
low[u]=lowu;
return lowu;
}
}Do;
bool done[maxn];
int d[maxn];
struct HeapNode{
int d,u;
bool operator<(const HeapNode& rhs)const {
return d<rhs.d;
}
};
void Dijkstra(int s,int n){
priority_queue<HeapNode>Q;
for(int i=0;i<=n;i++)d[i]=-inf;
d[s]=0;
memset(done,0,sizeof(done));
HeapNode inp;
inp.d=0;
inp.u=s;
Q.push(inp);
while(!Q.empty()){
HeapNode x=Q.top();
Q.pop();
int u=x.u;
if(done[u])continue;
done[u]=true;
for(int i=0;i<G[u].size();i++){
Edge &e=edges[G[u][i]];
if(done[e.to])continue;
if(d[e.to]<d[u]+e.dist){
d[e.to]=d[u]+e.dist;
inp.d=d[e.to];
inp.u=e.to;
Q.push(inp);
}
}
}
}
int solve(int n){
Dijkstra(1,n);
int max=-inf,p=1;
for(int i=1;i<=n;i++){
if(d[i]>max){
max=d[i];p=i;
}
}
Dijkstra(p,n);
max=-inf,p=1;
for(int i=1;i<=n;i++)if(d[i]>max){
max=d[i];p=i;
}
return max;
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){
Do.init(n);
int a,b;
for(int i=1;i<=m;i++){
scanf("%d%d",&a,&b);
add(a,b);
}
Do.dfs(1,-1,-1);
int tmp=solve(n);
printf("%d\n",cnt_bridge-tmp);
}
return 0;
}
/**
8 10
1 2
1 3
2 3
3 4
5 8
4 5
4 6
4 3
5 6
6 7
ans:0
8 9
1 2
1 3
2 3
3 4
5 8
4 5
4 6
5 6
6 7
ans:1
4 4
1 2
1 3
1 4
2 3
ans:0
**/