一般图最大匹配 带花树 2020牛客暑期多校训练营(第二场)i 1 or 2-尊龙凯时
标签(空格分隔): 一般图最大匹配
kuangbin的模板https://www.cnblogs.com/kuangbin/p/3278621.html
求一般图最大匹配,这道题的难点在于建图,把每个节点分成它的度个节点,把每条边分成两个节点,之后对于每条边,两个边分成的节点相连,边的两个端点的节点分别与其端点分成的度个节点相连之后求最大匹配,如果为完美匹配,则为yes,否则no。对于完美匹配,若一个边的一个端点不与由点分解的节点相连,那对映的另一个段点必与他匹配,否则就不是完美匹配了;若该边的的一个点与点分解的节点相连,则意味着这条边被选择,其另一端也必与点分解的节点相连;对于完美匹配,每个点分解的点都被连向边分解的点。这样一个符合条件的解就对应一个完美匹配。
参考https://www.cnblogs.com/xiongtao/p/11189452.html
#include
using namespace std;
const int maxn = 1e310;
int n,m;
int n;
bool graph[maxn][maxn];
int match[maxn];
bool inqueue[maxn],inpath[maxn],inblossom[maxn];
int head,tail;
int queue[maxn];
int start,finish;
int newbase;
int father[maxn],base[maxn];
int count;//匹配数,匹配对数是count/2
void push(int u)
{
queue[tail] = u;
tail;
inqueue[u] = true;
}
int pop()
{
int res = queue[head];
head;
return res;
}
int findcommonancestor(int u,int v)
{
memset(inpath,false,sizeof(inpath));
while(true)
{
u = base[u];
inpath[u] = true;
if(u == start) break;
u = father[match[u]];
}
while(true)
{
v = base[v];
if(inpath[v])break;
v = father[match[v]];
}
return v;
}
void resettrace(int u)
{
int v;
while(base[u] != newbase)
{
v = match[u];
inblossom[base[u]] = inblossom[base[v]] = true;
u = father[v];
if(base[u] != newbase) father[u] = v;
}
}
void bloosomcontract(int u,int v)
{
newbase = findcommonancestor(u,v);
memset(inblossom,false,sizeof(inblossom));
resettrace(u);
resettrace(v);
if(base[u] != newbase) father[u] = v;
if(base[v] != newbase) father[v] = u;
for(int tu = 1; tu <= n; tu)
if(inblossom[base[tu]])
{
base[tu] = newbase;
if(!inqueue[tu]) push(tu);
}
}
void findaugmentingpath()
{
memset(inqueue,false,sizeof(inqueue));
memset(father,0,sizeof(father));
for(int i = 1;i <= n;i)
base[i] = i;
head = tail = 1;
push(start);
finish = 0;
while(head < tail)
{
int u = pop();
for(int v = 1; v <= n; v)
if(graph[u][v] && (base[u] != base[v]) && (match[u] != v))
{
if((v == start) || ((match[v] > 0) && father[match[v]] > 0))
bloosomcontract(u,v);
else if(father[v] == 0)
{
father[v] = u;
if(match[v] > 0)
push(match[v]);
else
{
finish = v;
return;
}
}
}
}
}
void augmentpath()
{
int u,v,w;
u = finish;
while(u > 0)
{
v = father[u];
w = match[v];
match[v] = u;
match[u] = v;
u = w;
}
}
void edmonds()
{
memset(match,0,sizeof(match));
for(int u = 1; u <= n; u)
if(match[u] == 0)
{
start = u;
findaugmentingpath();
if(finish > 0)augmentpath();
}
}
void printmatch()
{
count = 0;
for(int u = 1; u <= n;u)
if(match[u] > 0)
count;
printf("%d\n",count);
for(int u = 1; u <= n; u)
if(u < match[u])
printf("%d %d\n",u,match[u]);
}
int main()
{
while(~scanf("%d%d",&n,&m)){
vector<int>vec[maxn];
memset(graph,false,sizeof(graph));
memset(match,0,sizeof(match));
memset(inqueue,0,sizeof(inqueue));
memset(inpath,0,sizeof(inpath));
memset(inblossom,0,sizeof(inblossom));
memset(base,0,sizeof(base));
memset(queue,0,sizeof(queue));
memset(father,0,sizeof(father));
head=tail=start=finish=count=newbase=0;
n=0;
for(int i=1;i<=n;i){
int d;
scanf("%d",&d);
while(d--){
vec[i].push_back(n);
}
}
for(int i=1;i<=m;i){
int u,v;
scanf("%d%d",&u,&v);
int f=n;
int t=n;
graph[f][t]=graph[t][f]=true;
for(int i=0;i<vec[u].size();i)
graph[vec[u][i]][f]=graph[f][vec[u][i]]=true;
for(int i=0;i<vec[v].size();i)
graph[vec[v][i]][t]=graph[t][vec[v][i]]=true;
}
edmonds();
int cnt=0;
for(int i=1;i<=n;i){
if(match[i]>0)
cnt;
}
if(cnt==n)
puts("yes");
else
puts("no");
}
}