最大权闭合子图
content
先作出以下声明:
c ( u , v ) : c(u,v): c(u,v): 边 ( u , v ) (u,v) (u,v) 的容量。
f ( u , v ) : f(u,v): f(u,v): 边 ( u , v ) (u,v) (u,v) 的流量。
[ S , T ] : [S,T]: [S,T]: 符号表示一个边集 { ( u , v ) ∣ ( u , v ) ∈ E , u ∈ S , v ∈ T } \Big\{(u,v)\ \Big |\ (u,v)\in E,u\in S,v\in T\Big\} {(u,v) ∣∣∣ (u,v)∈E,u∈S,v∈T}。
c [ S , T ] : c[S,T]: c[S,T]: 将流网络 G = ( V , E ) G=(V,E) G=(V,E) 的点集划分成 S , T ( S + T = V ) S,T(S+T=V) S,T(S+T=V) 两个完全不交的部分,源 s ∈ S s\in S s∈S,汇 t ∈ T t\in T t∈T,的割的容量。
容量最小的割即为一个网络的最小割。
问题引入:
一个有向图 G = ( V , E ) G=(V,E) G=(V,E) 的闭合图 G ′ ( V ′ , E ′ ) G'(V',E') G′(V′,E′) 是原图的一个点集,且该点集的所有出边仍指向该点集。
即 ∀ ( u , v ) ∈ E , u ∈ V ′ ⇒ v ∈ V ′ \forall_{(u,v)\in E},u\in V'\Rightarrow v\in V' ∀(u,v)∈E,u∈V′⇒v∈V′。
给每个点定义一个点权 w w w,最大权闭合图就是权和最大的闭合图,即最大化 ∑ v ∈ V ′ w v \sum_{v\in V'}w_v ∑v∈V′wv。
利用网络流的最小割进行快速求解,形式化的建图如下:
将图转化为网络
N
=
(
V
N
,
E
N
)
N=(V_N,E_N)
N=(VN,EN),添入源点汇点
s
,
t
s,t
s,t。
{
V
N
=
V
⋃
{
s
,
t
}
E
N
=
E
⋃
{
e
=
(
s
,
v
)
∣
v
∈
V
,
w
v
>
0
}
⋃
{
e
=
(
v
,
t
)
∣
v
∈
V
,
w
v
<
0
}
c
(
u
,
v
)
=
∞
e
=
(
u
,
v
)
∈
E
c
(
s
,
v
)
=
w
v
w
v
>
0
c
(
v
,
t
)
=
−
w
v
w
v
<
0
\begin{cases} V_N=V\bigcup \{s,t\}\\ E_N=E\bigcup \{e=(s,v)|v\in V,w_v>0\}\bigcup\{e=(v,t)|v\in V,w_v<0\}\\ c(u,v)=∞\quad\quad e=(u,v)\in E\\ c(s,v)=w_v\quad \quad w_v>0\\ c(v,t)=-w_v\quad\ w_v<0 \end{cases}
⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧VN=V⋃{s,t}EN=E⋃{e=(s,v)∣v∈V,wv>0}⋃{e=(v,t)∣v∈V,wv<0}c(u,v)=∞e=(u,v)∈Ec(s,v)=wvwv>0c(v,t)=−wv wv<0
定义:若一个
s
−
t
s-t
s−t 割满足割中每条边都只与源点或汇点相连,则称该割为简单割。
根据定义可得,网络 N N N 的简单割是不含原图 G G G 中边集 E E E 的任意一条边的。
-
引理1
网络 N N N 的最小割是简单割。
证明:
网络 N N N 的边分为与源或汇关联,容量有限和不与源汇关联(原边集 E E E 中所有边),容量无限的两种。
所有与源或汇关联的边组成的割集的容量是有限的,为所有点权的绝对值和。
最小割容量也至多为该绝对值和。
故最小割不可能取任何容量为正无限的边,即最小割是简单割。
作出以下声明:
记简单割 [ S , T ] [S,T] [S,T] 将网络 N N N 的点集 V N V_N VN 划分为点集 S S S 及其补集 T ( T = V N − S ) T(T=V_N-S) T(T=VN−S),且 s ∈ S , t ∈ T s\in S,t\in T s∈S,t∈T。
设闭合图为 V 1 V_1 V1,则其在 V V V 中补集为 V 1 ˉ \bar{V_1} V1ˉ。
记 V + V^+ V+ 为 V V V 中点权为正的点集, V − V^- V− 为 V V V 中点权为负的点集。
同样可以这么定义 V 1 + , V 1 − , V 1 ˉ + , V 1 ˉ − V_1^+,V_1^-,\bar{V_1}^+,\bar{V_1}^- V1+,V1−,V1ˉ+,V1ˉ−。
-
引理2
网络 N N N 的简单割 [ S , T ] [S,T] [S,T] 与图 G G G 的闭合图 V 1 V_1 V1 存在一一对应的关系。
即 V 1 ⋃ { s } = S V_1\bigcup \{s\}=S V1⋃{s}=S。证明:
-
闭合图对应简单割,即 S = V 1 ⋃ { s } , V 1 ˉ ⋃ { t } S=V_1\bigcup\{s\},\bar{V_1}\bigcup\{t\} S=V1⋃{s},V1ˉ⋃{t}。
反证法。若存在 ( u , v ) ∈ E , u ∈ S − { s } = V 1 , v ∈ T − { t } = V 1 ˉ (u,v)\in E,u\in S-\{s\}=V_1,v\in T-\{t\}=\bar{V_1} (u,v)∈E,u∈S−{s}=V1,v∈T−{t}=V1ˉ,使得 [ S , T ] [S,T] [S,T] 含不与源汇关联的边。则闭合图 V 1 V_1 V1 有一个后继不在闭合图内,矛盾。
-
简单割对应闭合图,即 V 1 = S − { s } V_1=S-\{s\} V1=S−{s} 是闭合图。
对于闭合图中 ∀ u ∈ V 1 \forall_{u\in V_1} ∀u∈V1,考虑任意一条由 u u u 引出的边 ( u , v ) ∈ E (u,v)\in E (u,v)∈E,由于简单割 [ S , T ] [S,T] [S,T] 不含 E E E 中任意一条边,所以 v ≠ T − { t } = V 1 ˉ v\neq T-\{t\}=\bar{V_1} v=T−{t}=V1ˉ。即 v ∈ V 1 v\in V_1 v∈V1,符合闭合图定义。
-
-
推论
c [ S , T ] = ∑ v ∈ V 1 ˉ + w v + ∑ v ∈ V 1 − ( − w v ) c[S,T]=\sum_{v\in \bar{V_1}^+}w_v+\sum_{v\in V_1^-}(-w_v) c[S,T]=v∈V1ˉ+∑wv+v∈V1−∑(−wv)
证明:
可以将割 [ S , T ] [S,T] [S,T] 按照与源汇的关联分为三个部分 : [ S , T ] = [ { s } , V 1 ˉ ] ⋃ [ { t } , V 1 ] ⋃ [ V 1 , V 1 ˉ ] :[S,T]=[\{s\},\bar{V_1}]\bigcup[\{t\},V_1]\bigcup[V_1,\bar{V_1}] :[S,T]=[{s},V1ˉ]⋃[{t},V1]⋃[V1,V1ˉ]。
由于 [ S , T ] [S,T] [S,T] 是简单割,所以 [ V 1 , V 1 ˉ ] = ∅ V_1,\bar{V_1}]=\empty V1,V1ˉ]=∅。
因为源只与点权为正的点相连,所以 [ { s } , V 1 ˉ ] = [ { s } , V 1 ˉ + ] [\{s\},\bar{V_1}]=[\{s\},\bar{V_1}^+] [{s},V1ˉ]=[{s},V1ˉ+]。
因为汇只与点权为负的点相连,所以 [ { t } , V 1 ] = [ { t } , V 1 − ] [\{t\},V_1]=[\{t\},V_1^-] [{t},V1]=[{t},V1−]。
-
定理
当网络 N N N 取最小割时,对应的闭合图达到最大权。
证明:
按照定义,闭合图的权和可以表示为: ∑ v ∈ V 1 + w v − ∑ v ∈ V 1 − ( − w v ) \sum_{v\in V_1^+}w_v-\sum_{v\in V_1^-}(-w_v) ∑v∈V1+wv−∑v∈V1−(−wv)。
w ( V 1 ) + c [ S , T ] = ∑ v ∈ V 1 + w v − ∑ v ∈ V 1 − ( − w v ) + ∑ v ∈ V 1 ˉ + w v + ∑ v ∈ V 1 − ( − w v ) w(V_1)+c[S,T]=\sum_{v\in V_1^+}w_v-\sum_{v\in V_1^-}(-w_v)+\sum_{v\in \bar{V_1}^+}w_v+\sum_{v\in V_1^-}(-w_v) w(V1)+c[S,T]=v∈V1+∑wv−v∈V1−∑(−wv)+v∈V1ˉ+∑wv+v∈V1−∑(−wv) = ∑ v ∈ V 1 + w v + ∑ v ∈ V 1 ˉ + w v = ∑ v ∈ V + w v =\sum_{v\in V_1^+}w_v+\sum_{v\in \bar{V_1}^+}w_v=\sum_{v\in V^+}w_v =v∈V1+∑wv+v∈V1ˉ+∑wv=v∈V+∑wv
即 w ( V 1 ) = ∑ v ∈ V + w v − c [ S , T ] w(V_1)=\sum_{v\in V^+}w_v-c[S,T] w(V1)=∑v∈V+wv−c[S,T]。因为 ∑ v ∈ V + w v \sum_{v\in V^+}w_v ∑v∈V+wv 是原图 G G G 中所有正权点之和,是常数。
所以最大化闭合图权和,就得最小化简单割的容量,而最小割是简单割。得证。
复杂度就是求最小割的复杂度。
exercise
#include <bits/stdc++.h>
using namespace std;
#define maxn 60005
#define inf 0x7f7f7f7f
queue < int > q;
struct node { int to, nxt, flow; }E[maxn << 3];
int head[maxn], cur[maxn], dep[maxn];
int n, m, s, t, cnt;
int read() {
int x = 0; char s = getchar();
while( s < '0' or s > '9' ) s = getchar();
while( '0' <= s and s <= '9' ) {
x = ( x << 1 ) + ( x << 3 ) + ( s ^ 48 );
s = getchar();
}
return x;
}
bool bfs() {
memset( dep, 0, sizeof( dep ) );
dep[s] = 1; q.push( s );
while( ! q.empty() ) {
int u = q.front(); q.pop();
for( int i = cur[u] = head[u];~ i;i = E[i].nxt ) {
int v = E[i].to;
if( ! dep[v] and E[i].flow ) {
dep[v] = dep[u] + 1;
q.push( v );
}
}
}
return dep[t];
}
int dfs( int u, int cap ) {
if( u == t or ! cap ) return cap;
int flow = 0;
for( int i = cur[u];~ i;i = E[i].nxt ) {
cur[u] = i; int v = E[i].to;
if( dep[v] == dep[u] + 1 ) {
int w = dfs( v, min( cap, E[i].flow ) );
if( ! w ) continue;
E[i ^ 1].flow += w;
E[i].flow -= w;
flow += w;
cap -= w;
if( ! cap ) break;
}
}
return flow;
}
int dinic() {
int ans = 0;
while( bfs() ) ans += dfs( s, inf );
return ans;
}
int id( int x, int y ) { return ( x - 1 ) * m + y; }
bool inside( int x, int y ) {
if( x < 1 or x > n or y < 1 or y > m ) return 0;
return 1;
}
void addedge( int u, int v, int w ) {
E[cnt] = { v, head[u], w };
head[u] = cnt ++;
E[cnt] = { u, head[v], 0 };
head[v] = cnt ++;
}
int main() {
memset( head, -1, sizeof( head ) );
scanf( "%d %d", &n, &m );
s = 0, t = n + m + 1;
int sum = 0;
for( int i = 1, x;i <= n;i ++ )
addedge( s, i, x = read() );
for( int i = 1;i <= m;i ++ ) {
int a = read(), b = read(), c = read();
addedge( a, i + n, inf );
addedge( b, i + n, inf );
addedge( i + n, t, c );
sum += c;
}
sum -= dinic();
printf( "%d\n", sum );
return 0;
}
最大密度子图
content
问题引入:
给定一张图 G = ( V , E ) G=(V,E) G=(V,E),从中选一个子图 G ′ = ( V ′ , E ′ ) G'=(V',E') G′=(V′,E′) 使得其密度 D = ∣ E ′ ∣ ∣ V ′ ∣ D=\frac{|E'|}{|V'|} D=∣V′∣∣E′∣ 最大。最大化并输出这个 D D D。
重新函数化上述式子: D = f ( x ) = ∑ e ∈ E x e ∑ v ∈ V x v , x ∈ { 0 , 1 } D=f(x)=\frac{\sum_{e\in E}x_e}{\sum_{v\in V}x_v},x\in\{0,1\} D=f(x)=∑v∈Vxv∑e∈Exe,x∈{0,1}。
以下简记 ∣ V ∣ = n , ∣ E ∣ = m |V|=n,|E|=m ∣V∣=n,∣E∣=m。
这个式子跟 0/1分数规划
有着异曲同工之妙。
同样考虑二分结果 g g g。
记: h ( g ) = max x { ∑ e ∈ E x e − ∑ v ∈ V x v ∗ g } h(g)=\max_x\Big\{\sum_{e\in E}x_e-\sum_{v\in V}x_v*g\Big\} h(g)=maxx{∑e∈Exe−∑v∈Vxv∗g}。
记:问题最终答案为
a
n
s
ans
ans,则
∀
G
′
=
(
n
,
m
)
m
n
≤
a
n
s
\forall_{G'=(n,m)}\frac{m}{n}\le ans
∀G′=(n,m)nm≤ans。
{
h
(
g
)
=
0
⇒
g
=
a
n
s
h
(
g
)
>
0
⇒
g
<
a
n
s
h
(
g
)
<
0
⇒
g
>
a
n
s
\begin{cases} h(g)=0\Rightarrow g=ans\\ h(g)>0\Rightarrow g<ans\\ h(g)<0\Rightarrow g>ans \end{cases}
⎩⎪⎨⎪⎧h(g)=0⇒g=ansh(g)>0⇒g<ansh(g)<0⇒g>ans
确定二分查找范围:
[
1
n
,
m
1
]
[\frac{1}{n},\frac{m}{1}]
[n1,1m]。
确定精度误差: 1 n 2 \frac{1}{n^2} n21。
-
引理1
无向图 G G G 中,任意两个具有不同密度的子图 G 1 , G 2 G_1,G_2 G1,G2,其密度差不小于 1 n 2 \frac{1}{n^2} n21。
证明:
不妨假设 G 1 G_1 G1 子图的密度大于 G 2 G_2 G2 子图的密度。
m 1 n 1 − m 2 n 2 = m 1 n 2 − m 2 n 1 n 1 n 2 ≥ 1 n 1 n 2 ≥ 1 n 2 \frac{m_1}{n_1}-\frac{m_2}{n_2}=\frac{m_1n_2-m_2n_1}{n_1n_2}\ge \frac{1}{n_1n_2}\ge\frac{1}{n^2} n1m1−n2m2=n1n2m1n2−m2n1≥n1n21≥n21
-
推论
对于无向图 G G G 而言,如果存在密度为 D D D 的子图 G ′ G' G′,且不存在密度 ≥ D \ge D ≥D 的子图,则 G ′ G' G′ 为最大密度子图。
接下来考虑如何求解二分答案对应的最大子图密度值 h ( g ) h(g) h(g)。
-
引理2
当点集确定时,点集的诱导子图一定是最优解。
诱导子图:从原图 G < V , E > G<V,E> G<V,E> 中选出一个子图 G ′ = ( V ′ , E ′ ) G'=(V',E') G′=(V′,E′), ∀ u , v ∈ V ′ \forall_{u,v\in V'} ∀u,v∈V′ 必有 e = ( u , v ) ∈ E ′ e=(u,v)\in E' e=(u,v)∈E′,即全选子图点集内部的边。
考虑假设点集被确定为 V ′ V' V′,如何继续求解子图 G ′ = ( V ′ , E ′ ) G'=(V',E') G′=(V′,E′)。
正向思维就是直接把点集中两两点之间的边选出来。但这里我们不采取这样的做法,因为暴力无法优化。
考虑逆向思维,将与点集 V ′ V' V′ 相关的所有边集去除掉不是 E ′ E' E′ 中的边集。
具体而言,用 ∑ v ∈ V ′ d v − \sum_{v\in V'}d_v- ∑v∈V′dv− 红色边再除以 2 2 2, d i : i d_i:i di:i 点的度数。除以 2 2 2 是因为 E E E 的边被两个端点都算了一次。
红色边的图上意义就是连接 V V V 和 V − V ′ V-V' V−V′ 两个完全不交的点集的边。
这就有一种「割」的意味了。
由于是要最大化 ∣ E ′ ∣ − g ⋅ ∣ V ′ ∣ |E'|-g·|V'| ∣E′∣−g⋅∣V′∣,乘以 − 1 -1 −1 ,转化为最小化 g ⋅ ∣ V ′ ∣ − ∣ E ′ ∣ g·|V'|-|E'| g⋅∣V′∣−∣E′∣。
g ⋅ ∣ V ′ ∣ − ∣ E ′ ∣ = ∑ v ∈ V ′ g − ∑ e ∈ E ′ 1 = ∑ v ∈ V ′ g − ∑ v ∈ V ′ d v − c [ V ′ , V − V ′ ] 2 g·|V'|-|E'|=\sum_{v\in V'}g-\sum_{e\in E'}1=\sum_{v\in V'}g-\frac{\sum_{v\in V'}d_v-c[V',V-V']}{2} g⋅∣V′∣−∣E′∣=v∈V′∑g−e∈E′∑1=v∈V′∑g−2∑v∈V′dv−c[V′,V−V′] = 1 2 ( ∑ v ∈ V ′ ( 2 g − d v ) + c [ V ′ , V − V ′ ] ) =\frac{1}{2}\Big(\sum_{v\in V'}(2g-d_v)+c[V',V-V']\Big) =21(v∈V′∑(2g−dv)+c[V′,V−V′])
∑ v ∈ V ′ ( 2 g − d v ) \sum_{v\in V'}(2g-d_v) ∑v∈V′(2g−dv),就是选了 v v v,就要花费代价 2 g − d v 2g-d_v 2g−dv, 这相当于每个点多了个 2 g − d v 2g-d_v 2g−dv 的点权。
常见处理,让 V ′ V' V′ 中的点都与 t t t 相连,把点权赋成边权。
由于最小割只接受非负边权,但点权可能为负数,那么就把所有边权都加上一个极大值 B i g Big Big,保证非负,最后再减去即可。
总结,形式化地将图
G
=
(
V
,
E
)
G=(V,E)
G=(V,E) 转化为网络
N
=
(
V
N
,
E
N
)
N=(V_N,E_N)
N=(VN,EN):
{
V
N
=
V
⋃
{
s
,
t
}
E
N
=
{
(
u
,
v
)
∣
(
u
,
v
)
∈
E
}
⋃
{
(
s
,
v
)
∣
v
∈
V
}
⋃
{
(
v
,
t
)
∣
v
∈
V
}
c
(
u
,
v
)
=
1
(
u
,
v
)
∈
E
c
(
s
,
v
)
=
B
i
g
v
∈
V
c
(
v
,
t
)
=
B
i
g
+
2
g
−
d
v
v
∈
V
\begin{cases}V_N=V\bigcup\{s,t\}\\E_N=\{(u,v)|(u,v)\in E\}\bigcup\{(s,v)|v\in V\}\bigcup\{(v,t)|v\in V\}\\c(u,v)=1\quad\quad\quad\quad\quad\quad(u,v)\in E\\c(s,v)=Big\quad\quad\quad\quad\quad\ v\in V\\c(v,t)=Big+2g-d_v\quad v\in V\end{cases}
⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧VN=V⋃{s,t}EN={(u,v)∣(u,v)∈E}⋃{(s,v)∣v∈V}⋃{(v,t)∣v∈V}c(u,v)=1(u,v)∈Ec(s,v)=Big v∈Vc(v,t)=Big+2g−dvv∈V
-
引理3
网络 N N N 的一个割 [ S , T ] [S,T] [S,T] 与原图 G G G 的子图 G ′ = ( V ′ , E ′ ) G'=(V',E') G′=(V′,E′) 方案存在一一对应关系。即 V ′ ⋃ { s } = S V'\bigcup\{s\}=S V′⋃{s}=S。
因为割可以是任意划分的,子图也可以是任意划分的。
-
定理
网络 N N N 的一个最小割 [ S , T ] [S,T] [S,T] ,其根据
引理2
所对应子图 G ′ G' G′ 是 h ( g ) h(g) h(g) 的一个最优解。证明:
设 c [ S , T ] c[S,T] c[S,T] 为网络 N N N 的任意一个割的容量。根据
引理3
V ’ = S − { s } , V ′ ˉ = T − { t } V’=S-\{s\},\bar{V'}=T-\{t\} V’=S−{s},V′ˉ=T−{t}。
c [ S , T ] = ∑ u ∈ S , v ∈ T c ( u , v ) = ∑ v ∈ V ′ ˉ c ( s , v ) + ∑ v ∈ V ′ c ( v , t ) + ∑ u ∈ V ′ , v ∈ V ′ ˉ , ( u , v ) ∈ E c ( u , v ) c[S,T]=\sum_{u\in S,v\in T}c(u,v)=\sum_{v\in \bar{V'}}c(s,v)+\sum_{v\in V'}c(v,t)+\sum_{u\in V',v\in \bar{V'},(u,v)\in E}c(u,v) c[S,T]=u∈S,v∈T∑c(u,v)=v∈V′ˉ∑c(s,v)+v∈V′∑c(v,t)+u∈V′,v∈V′ˉ,(u,v)∈E∑c(u,v) = ∑ v ∈ V ′ ˉ B i g + ∑ v ∈ V ′ B i g + 2 g − d v + ∑ u ∈ V ′ , v ∈ V ′ ˉ , ( u , v ) ∈ E 1 =\sum_{v\in \bar{V'}}Big+\sum_{v\in V'}Big+2g-d_v+\sum_{u\in V',v\in \bar{V'},(u,v)\in E}1 =v∈V′ˉ∑Big+v∈V′∑Big+2g−dv+u∈V′,v∈V′ˉ,(u,v)∈E∑1 = B i g ⋅ ∣ V ∣ + ∑ u ∈ V ′ ( 2 g − d u + ∑ v ∈ V ′ ˉ , ( u , v ) ∈ E 1 ) =Big·|V|+\sum_{u\in V'}\Big(2g-d_u+\sum_{v\in \bar{V'},(u,v)\in E}1\Big) =Big⋅∣V∣+u∈V′∑(2g−du+v∈V′ˉ,(u,v)∈E∑1) = B i g ⋅ ∣ V ∣ + ∑ u ∈ V ′ ( 2 g − ∑ v ∈ V ′ , ( u , v ) ∈ E 1 ) =Big·|V|+\sum_{u\in V'}\Big(2g-\sum_{v\in V',(u,v)\in E}1\Big) =Big⋅∣V∣+u∈V′∑(2g−v∈V′,(u,v)∈E∑1) = B i g ∗ n + 2 g ∣ V ′ ∣ − 2 ∣ E ′ ∣ =Big*n+2g|V'|-2|E'| =Big∗n+2g∣V′∣−2∣E′∣ = U ∗ n − 2 ( ∣ E ′ ∣ − g ∣ V ′ ∣ ) =U*n-2(|E'|-g|V'|) =U∗n−2(∣E′∣−g∣V′∣)
E ′ E' E′ 已重定义为 V ′ V' V′ 的导出子图的边集。U ∗ n U*n U∗n 为定值,当割取最小的时候, 2 ( ∣ E ′ ∣ − g ∣ V ′ ∣ ) 2(|E'|-g|V'|) 2(∣E′∣−g∣V′∣) 取最大。即 h ( g ) = U ∗ n − c [ S , T ] 2 h(g)=\frac{U*n-c[S,T]}{2} h(g)=2U∗n−c[S,T],其中 [ S , T ] [S,T] [S,T] 为最小割。
参考选摘:胡伯涛《最小割模型在信息学竞赛中的应用》
exercise
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define maxn 100005
struct node { int to, nxt; double flow; }E[maxn];
struct Node { int u, v; }edge[maxn];
queue < int > q;
int n, m, s, t, cnt;
int head[maxn], cur[maxn], dep[maxn], d[maxn];
bool vis[maxn];
void addedge( int u, int v, double w1, double w2 ) {
E[cnt] = { v, head[u], w1 };
head[u] = cnt ++;
E[cnt] = { u, head[v], w2 };
head[v] = cnt ++;
}
void build( double g ) {
memset( head, -1, sizeof( head ) ); cnt = 0;
for( int i = 1;i <= m;i ++ ) addedge( edge[i].u, edge[i].v, 1, 1 );
for( int i = 1;i <= n;i ++ ) addedge( s, i, m, 0 ), addedge( i, t, m + 2 * g - d[i], 0 );
}
bool bfs() {
memset( dep, 0, sizeof( dep ) );
dep[s] = 1; q.push( s );
while( ! q.empty() ) {
int u = q.front(); q.pop();
for( int i = cur[u] = head[u];~ i;i = E[i].nxt ) {
int v = E[i].to;
if( ! dep[v] and E[i].flow > 0 ) {
dep[v] = dep[u] + 1;
q.push( v );
}
}
}
return dep[t];
}
double dfs( int u, double cap ) {
if( u == t or cap <= 0 ) return cap;
double flow = 0;
for( int i = cur[u];~ i;i = E[i].nxt ) {
cur[u] = i; int v = E[i].to;
if( dep[v] == dep[u] + 1 ) {
double w = dfs( v, min( cap, E[i].flow ) );
if( w <= 0 ) continue;
E[i ^ 1].flow += w;
E[i].flow -= w;
flow += w;
cap -= w;
if( cap <= 0 ) break;
}
}
return flow;
}
double dinic( double g ) {
build( g );
double ans = 0;
while( bfs() ) ans += dfs( s, 2e9 );
return ans;
}
void dfs( int now ) {
if( vis[now] ) return;
vis[now] = 1;
if( now ^ s ) cnt ++;
for( int i = head[now];~ i;i = E[i].nxt )
if( E[i].flow > 0 ) dfs( E[i].to );
}
int main() {
while( ~ scanf( "%d %d", &n, &m ) ) {
s = 0, t = n + 1;
for( int i = 0;i <= n;i ++ ) vis[i] = d[i] = 0;
for( int i = 1, u, v;i <= m;i ++ ) {
scanf( "%d %d", &u, &v );
edge[i] = { u, v };
d[u] ++, d[v] ++;
}
double l = 0, r = m, eps = 1.0 / double(n * n);
while( r - l > eps ) {
double mid = ( l + r ) / 2;
if( m * n - dinic( mid ) > eps ) l = mid;
else r = mid;
}
dinic( l );
cnt = 0;
dfs( s );
if( ! cnt ) printf( "1\n1\n" );
else {
printf( "%d\n", cnt );
for( int i = 1;i <= n;i ++ )
if( vis[i] ) printf( "%d\n", i );
}
}
return 0;
}