Codeforces Gym 101630C Connections 强连通分量Tarjan

Problem C. Connections

Input file: standard input
Output file: standard output
Time limit: 3 seconds
Memory limit: 512 mebibytes

Hard times are coming to Byteland. Quantum computing is becoming mainstream and Qubitland is going to occupy Byteland. The main problem is that Byteland does not have enough money for this war, so the King of Byteland Byteman 0x0B had decided to reform its road system to reduce expenses.
Byteland has n cities that are connected by m one-way roads and it is possible to get from any city to any other city using these roads. No two roads intersect outside of the cities and no other roads exist. By the way, roads are one-way because every road has a halfway barrier that may be passed in one direction only. These barriers are intended to force enemies to waste their time if they choose the wrong way.
The idea of the upcoming road reform is to abandon some roads so that exactly 2n roads remain. Advisers of the King think that it should be enough to keep the ability to get from any city to any other city. (Maybe even less is enough? They do not know for sure.) The problem is how to choose roads to abandon.
Everyone in Byteland knows that you are the only one who can solve this problem.

Input

Input consists of several test cases. The first line of the input contains the number of tests cases.
The first line of each test case contains n and m — the number of cities and the number of roads correspondingly (n ≥ 4, m > 2n). Each of the next m lines contains two numbers xi and yi denoting a road from city xi to city yi (1 ≤ xi, yi ≤ n, xi 6= yi). It is guaranteed that it is possible to get from any city to any other city using existing roads only. For each pair (x, y) of cities there is at most one road going from city x to city y and at most one road going from city y to city x. The solution is guaranteed to exist. The sum of m over all test cases in a single input does not exceed 100 000.

Output

For each test case output m − 2n lines. Each line describes a road that should be abandoned. Print the road in the same format as in the input: the number of the source city and the number of the destination city. The order of roads in the output does not matter, but each road from the input may appear in the output at most once and each road in the output must have been in the input. It still must be possible to get from any city to any other city using the remaining roads.

Sample InputSample Output
1
4 9
1 2
1 3
2 3
2 4
3 2
3 4
4 1
4 2
4 3
1 3

给出一个有向强连通图,要求留下2*n条边使其仍然强连通。


利用tarjan求出dfn和low。做Tarjan算法的过程中,会留下一棵生成树,这棵树上的所有边肯定都要保留(保证根可以到所有点)。

其次,对于每个节点now,留下一条反向连到low[now]的边。这样可以保证其通向树根。


#include <cstdio>
#include <iostream>
#include <string.h>
#include <string> 
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#include <assert.h>
#define pb push_back 
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
typedef pair<int,int> pp;
const int maxn=100005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
const ld pi=acos(-1.0L);
int x[maxn],y[maxn],head[maxn];
bool del[maxn];
int dfn[maxn],low[maxn];
bool inst[maxn];
map<ll,int> mp;
int num=0;

struct Edge {
    int from,to,pre;
};
Edge edge[maxn*2];

void addedge(int from,int to) {
    edge[num]=(Edge){from,to,head[from]};
    head[from]=num++;
//  cout << num-1 << ' ' << from << ' ' << to << endl;
}

stack<int> st;
void tarjan(int now) {
    num++;
    dfn[now]=low[now]=num;
    inst[now]=1;
    st.push(now);
    int rem=-1;
    for (int i=head[now];i!=-1;i=edge[i].pre) {
        int to=edge[i].to;
        if (!dfn[to]) {
            tarjan(to);
            del[i]=1;
            low[now]=min(low[now],low[to]);
        }
        else if (inst[to]) {
            if (low[now]>low[to]) rem=i; 
            low[now]=min(low[now],dfn[to]); 
        }
    }
    if (rem!=-1) del[rem]=1;
    if (dfn[now]==low[now]) {
        inst[now]=0;
        while (st.top()!=now) {
            inst[st.top()]=0;
            st.pop();
        }
        st.pop();
    }
}

int main() {
    int cas;
    scanf("%d",&cas);
    memset(head,-1,sizeof(head));
    while (cas--) {
        int n,m;
        scanf("%d%d",&n,&m);
        mem0(dfn);mem0(low);mem0(inst);
        num=1;
        for (int i=1;i<=m;i++) {
            scanf("%d%d",&x[i],&y[i]);
            addedge(x[i],y[i]);
            del[i]=0;
        }
        tarjan(1);
        int cnt=0;
        for (int i=1;i<=m;i++) {
            if (!del[i]) {
                printf("%d %d\n",x[i],y[i]);
                cnt++;
            }
            if (m-cnt==2*n) break;
        }
        assert(m-cnt==2*n);
        for (int i=1;i<=n;i++) head[i]=-1;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值