二分图的构造

Bigraph Extension HDU - 7135

有一个2*n(n为偶数,n < 1e3)个点的二分图,已经连好了m条边,这m条边保证任意两条边不含公共点。
求最少添加多少条边,使得这个图任意两点连通,且最长简单路径所含边数 > n。输出最小字典序的方案。



``
`





`



``

``

``
思路,不难想到是要建一个2*n的环。那么此题关键点是要构造字典序最小的方案,那么我们每次找字典序最小的点来建边即可。用并查集维护,保证连的点不成环。
那么对于最后一条边,也就是两个度数为1的点连边使图成环即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/*
* @Author: Marhoosh
* @Date: 2021-10-11 11:00:11
* @Last Modified by: Marhoosh
* @Last Modified time: 2021-10-30 15:52:27
*/
#include<bits/stdc++.h>
using namespace std;
#define Debug(x) cout<<#x<<':'<<x<<endl
#define INF 0x7fffffff
typedef long long ll;
typedef pair<ll,ll> P;
const ll maxn=2e3+11;
vector<P> ans;
ll fa[maxn],d[maxn];
ll n,m;
ll found(ll x){return fa[x]==x?x:fa[x]=found(fa[x]);}
void solve1(){
ll e=0;
for(ll i=1;i<=n;i++){
while(d[i]<2){
for(ll j=n+1;j<=2*n;j++){
if(d[j]<2){
ll fi=found(i),fj=found(j);
if(fi==fj) continue;
d[i]++,d[j]++;
ans.push_back({i,j});
//cout<<i<<" "<<j<<endl;
fa[fi]=fj;
e++;
if(e>=2*n-m-1) return ;
break;
}
}
}
}
}
void solve2(){
ll u,v;
for(ll i=1;i<=2*n;i++){
if(d[i]==1){u=i;break;}
}
for(ll i=1;i<=2*n;i++){
if(d[i]==1 && i!=u){v=i;break;}
}
ans.push_back({u,v});
cout<<ans.size()<<endl;
for(auto i=ans.begin();i!=ans.end();i++){
cout<<(*i).first<<" "<<(*i).second-n<<endl;
}
return ;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
ll ca;cin>>ca;
while(ca--){
cin>>n>>m;
for(ll i=1;i<=2*n;i++) fa[i]=i;
ans.clear();memset(d,0,sizeof(d));
for(ll i=1;i<=m;i++){
ll u,v;cin>>u>>v;
v=v+n;
d[u]++,d[v]++;
fa[u]=v;
}
solve1();
solve2();
}
return 0;
}