生活随笔
收集整理的這篇文章主要介紹了
nowcoder 清楚姐姐的翅膀们 F 一般图的最大匹配
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
傳送門
文章目錄
題意
思路:
這個題很容易就會掉到二分圖匹配的坑里。。
但實際上這個是一個一般圖匹配。
考慮將妹子拆點,一個入點一個出點,入點出點都連蝴蝶結(jié)。
我們看看最終會有三種匹配情況:
(1)(1)(1)妹子自身匹配,匹配數(shù)+1+1+1。
(2)(2)(2)一個妹子的出點或入點其中一個和蝴蝶結(jié)匹配,匹配數(shù)+1+1+1。
(3)(3)(3)一個妹子的出點和入點都和蝴蝶結(jié)匹配,匹配數(shù)+2+2+2。
可以發(fā)現(xiàn),最終有貢獻(xiàn)的只有(3)(3)(3),所以求一個最大匹配讓后減去nnn即可。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<chrono>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=1000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;template <typename T>
class graph {public:struct edge {int from
;int to
;T cost
;};vector
<edge
> edges
;vector
<vector
<int> > g
;int n
;graph(int _n
) : n(_n
) { g
.resize(n
); }virtual int add(int from
, int to
, T cost
) = 0;
};
template <typename T>
class undirectedgraph : public graph<T> {public:using graph
<T
>::edges
;using graph
<T
>::g
;using graph
<T
>::n
;undirectedgraph(int _n
) : graph
<T
>(_n
) {}int add(int from
, int to
, T cost
= 1) {assert(0 <= from
&& from
< n
&& 0 <= to
&& to
< n
);int id
= (int)edges
.size();g
[from
].push_back(id
);g
[to
].push_back(id
);edges
.push_back({from
, to
, cost
});return id
;}
};
template <typename T>
vector
<int> find_max_unweighted_matching(const undirectedgraph
<T
> &g
) {std
::mt19937
rng(chrono
::steady_clock
::now().time_since_epoch().count());vector
<int> match(g
.n
, -1); vector
<int> aux(g
.n
, -1); vector
<int> label(g
.n
); vector
<int> orig(g
.n
); vector
<int> parent(g
.n
, -1); queue
<int> q
;int aux_time
= -1;auto lca
= [&](int v
, int u
) {aux_time
++;while (true) {if (v
!= -1) {if (aux
[v
] == aux_time
) { return v
;}aux
[v
] = aux_time
;if (match
[v
] == -1) {v
= -1;} else {v
= orig
[parent
[match
[v
]]]; }}swap(v
, u
);}}; auto blossom
= [&](int v
, int u
, int a
) {while (orig
[v
] != a
) {parent
[v
] = u
;u
= match
[v
];if (label
[u
] == 1) { label
[u
] = 0;q
.push(u
);}orig
[v
] = orig
[u
] = a
; v
= parent
[u
];}}; auto augment
= [&](int v
) {while (v
!= -1) {int pv
= parent
[v
];int next_v
= match
[pv
];match
[v
] = pv
;match
[pv
] = v
;v
= next_v
;}}; auto bfs
= [&](int root
) {fill(label
.begin(), label
.end(), -1);iota(orig
.begin(), orig
.end(), 0);while (!q
.empty()) {q
.pop();}q
.push(root
);label
[root
] = 0;while (!q
.empty()) {int v
= q
.front();q
.pop();for (int id
: g
.g
[v
]) {auto &e
= g
.edges
[id
];int u
= e
.from
^ e
.to
^ v
;if (label
[u
] == -1) { label
[u
] = 1; parent
[u
] = v
;if (match
[u
] == -1) { augment(u
); return true;}label
[match
[u
]] = 0;q
.push(match
[u
]);continue;} else if (label
[u
] == 0 && orig
[v
] != orig
[u
]) {int a
= lca(orig
[v
], orig
[u
]);blossom(u
, v
, a
);blossom(v
, u
, a
);}}}return false;}; auto greedy
= [&]() {vector
<int> order(g
.n
);iota(order
.begin(), order
.end(), 0);shuffle(order
.begin(), order
.end(), rng
);for (int i
: order
) {if (match
[i
] == -1) {for (auto id
: g
.g
[i
]) {auto &e
= g
.edges
[id
];int to
= e
.from
^ e
.to
^ i
;if (match
[to
] == -1) {match
[i
] = to
;match
[to
] = i
;break;}}}}}; greedy();for (int i
= 0; i
< g
.n
; i
++) {if (match
[i
] == -1) {bfs(i
);}}return match
;
}int main() {ios
::sync_with_stdio(0), cin
.tie(0);int _
; cin
>>_
;while(_
--) {int n
,m
; cin
>>n
>>m
;undirectedgraph
<int>g(n
*2+m
);for(int i
=0;i
<n
;i
++) {g
.add(i
,i
+n
,1);int c
; cin
>>c
;while(c
--) {int x
; cin
>>x
;x
--;g
.add(i
,2*n
+x
);g
.add(i
+n
,2*n
+x
);}}auto blossom_match
= find_max_unweighted_matching(g
);int ans
=0;for(int i
=0;i
<blossom_match
.size();i
++) {if(blossom_match
[i
]!=-1) ans
++;}cout
<<ans
/2-n
<<endl
;}
}
總結(jié)
以上是生活随笔為你收集整理的nowcoder 清楚姐姐的翅膀们 F 一般图的最大匹配的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。