HDU 5409
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5409
题意:
给一个图一些边,保证图连通
问对于每条边,如果去除该边后使得图中一些点不连通。设这些点(u,v),要求使u尽量小,v尽量大,输出这样的(u,v)。否则输出0 0。
思路:
感谢http://www.cnblogs.com/oneshot/p/4748840.html
基本的思路就是找桥,然后桥两端找找对应的最大u和最小v。
自己写的时候写完找桥就不会了,而且找桥找的特别菜~
有一个思路,即找出两边最大的u,设为u1和u2。则u = min(u1,u2),v = u+1。
证明:去掉桥以后,原图变成两个连通图。因为u越大越好所以取两个图中的最大 点,因为v必须大于u所以u只能取两个连通图中更小的u。设u1<u2。则在 第二个连通图中,一定能找到一个点u+1满足v最小。否则能用u+1来更新u1,使得u1更大。
因为对于每个桥割开的连通图内,只需要表现它最大点u的性质,所以可以强连通缩点, 最后再在缩成的“点”之间连桥。这样原图就变成一棵树,然后就变成树的遍历问题,
加个回溯就可以求出u,v。
缩点主要是给每个点设了个ID值,表示它属于哪一个新点。然后把需要的性质传给新 点就可以。
源码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <utility>
#include <string>
#include <vector>
using namespace std;
#define gmin(a,b) ((a) < (b) ? (a) : (b))
#define gmax(a,b) ((a) > (b) ? (a) : (b))
const int MAXN = 1e5 + 5;
typedef pair<int, int>pii;
vector<pii>lin[MAXN];
int n, m;
int bridge[MAXN];
int U[MAXN], V[MAXN];
int low[MAXN], pre[MAXN], clock;
int NewId[MAXN], vis[MAXN], IDs;
int maxu[MAXN], ans[MAXN];
void edge_init()
{
for(int i = 1 ; i <= n ; i++)
lin[i].clear();
int u, v;
for(int i = 1 ; i <= m ; i++){
scanf("%d%d", &u, &v);
lin[u].push_back(make_pair(v, i));
lin[v].push_back(make_pair(u, i));
U[i] = u, V[i] = v;
}
}
void DFS_bridge(int u, int fa)
{
pre[u] = low[u] = ++clock;
for(int i = 0 ; i < (int)lin[u].size() ; i++){
pii temp = lin[u][i];
int v = temp.first, ID = temp.second;
if(pre[v] == 0){
DFS_bridge(v, u);
low[u] = gmin(low[u], low[v]);
if(low[v] > pre[u]) bridge[ID] = 1;
}
else if(pre[v] != 0 && v != fa)
low[u] = gmin(low[u], pre[v]);
}
}
void DFS_shrink(int u, int fa)
{
NewId[u] = IDs;
vis[u] = 1;
for(int i = 0 ; i < (int)lin[u].size() ; i++){
int v = lin[u][i].first;
int ID = lin[u][i].second;
if(!bridge[ID] && v != fa && vis[v] == 0){
DFS_shrink(v, u);
}
}
}
void BCC_bridge()
{
memset(bridge, 0, sizeof(bridge));
memset(pre, 0, sizeof(pre));
clock = 0;
DFS_bridge(1, -1);
}
void Shrink()
{
memset(vis, 0, sizeof(vis));
IDs = 0;
for(int i = 1 ; i <= n ; i++){
if(vis[i] == 0){
++IDs;
DFS_shrink(i, -1);
}
}
for(int i = 1 ; i <= n ; i++)
lin[i].clear();
for(int i = 1 ; i <= m ; i++){
if(bridge[i]){
int u = NewId[U[i]], v = NewId[V[i]];
lin[u].push_back(make_pair(v, i));
lin[v].push_back(make_pair(u, i));
}
}
}
void DFS(int u, int fa)
{
ans[u] = maxu[u];
pre[u] = ++clock;
for(int i = 0 ; i < (int)lin[u].size() ; i++){
int v = lin[u][i].first;
if(v != fa && pre[v] == 0){
DFS(v, u);
ans[u] = gmax(ans[u], ans[v]);
}
}
}
int main()
{
int t;
scanf("%d", &t);
while(t--){
scanf("%d%d", &n, &m);
edge_init();
BCC_bridge();
Shrink();
// for(int i = 1 ; i <= m ; i++)
// printf("U[%d] = %d, V[%d] = %d, bridge = %d\n", i, U[i], i, V[i], bridge[i]);
memset(maxu, 0, sizeof(maxu));
for(int i = 1 ; i <= n ; i++)
maxu[NewId[i]] = gmax(maxu[NewId[i]], i);
int u;
for(u = 1 ; u <= IDs ; u++)
if(maxu[u] == n)
break;
clock = 0;
memset(pre, 0, sizeof(pre));
DFS(u, -1);
for(int i = 1 ; i <= m ; i++){
if(!bridge[i]){
printf("0 0\n");
}
else{
int u = NewId[U[i]], v = NewId[V[i]];
if(pre[u] < pre[v])
swap(u, v);
printf("%d %d\n", ans[u], ans[u] + 1);
}
}
}
return 0;
}