2020牛客多校第一场I题1 or 2(一般图匹配)
题意:给你n个点m条边以及n个点的度(只为1或者2),选择一些边满足点的度要求,若能满足输出YES,反之NO;
题解:我们把点和边都进行拆分
例子:
3 2 1 1 2 1 3 2 3
点按照度,边拆分成两个点,跑一遍一般图的最大匹配,若能完美匹配就是YES
完美匹配就是所有点都能匹配 通俗点就是所有点都是一对一对的
#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 507; const int M = 507*507*2; struct node{int to,nxt;}g[M]; int head[N],cnt; int vis[N],match[N],f[N],pre[N],Id,id[N]; int dd[N]; int nodes[N][N]; //vis[i]: 0(未染色) 1(黑色) 2(白色) //match[i]: i的匹配点 //f[i]: i在带花树中的祖先 //pre[i]: i的非匹配边的另一点 //id: 找LCA用 int n,m,ans,u,v,tot; queue<int> q; void Init(){ Id=ans=cnt=tot=0; memset(nodes,0,sizeof(nodes)); memset(head,-1,sizeof(head)); memset(id,0,sizeof(id)); memset(match,0,sizeof(match)); memset(dd,0,sizeof(dd)); // for(int i=1;i<=n;i++) // head[i]=-1,id[i]=match[i]=dd[i]=0; } void add(int u,int v){ g[cnt]=node{v,head[u]},head[u]=cnt++; } int getf(int x){ return f[x]==x?x:f[x]=getf(f[x]); } //查询x和y在带花树中的LCA int LCA(int x,int y){ //沿着增广路向上找lca for(++Id;;swap(x,y))//x,y交替向上 if(x) { x=getf(x);//有可能环中有环(花中有花),所以用并查集找祖先,只处理祖先节点 if(id[x]==Id) return x; //x,y在同一环中,一定会找到已被编号的点,该点即为LCA。 else id[x]=Id,x=pre[match[x]];//给点编号,并沿着非匹配边向上找 } } //缩点(开花),将x、y到LCA(l)路径中的点,缩为一点 void blossom(int x,int y,int l){ while(getf(x)!=l){ //增广路取反 pre[x]=y,y=match[x]; //如果x、y的奇环中有白点,将其染为黑点,放入队列,让其去找不是环中的匹配点 if(vis[y]==2) vis[y]=1,q.push(y); //只改变是根的点 if(getf(x)==x) f[x]=l; if(getf(y)==y) f[y]=l; //增广路取反 x=pre[y]; } } bool aug(int s){ //puts("s"); //每次都以s为起点bfs,建带花树 for(int i=1;i<=n;i++) vis[i]=pre[i]=0,f[i]=i; while(!q.empty()) q.pop(); q.push(s),vis[s]=1; while(!q.empty()){ u=q.front();q.pop(); for(int i=head[u];~i;i=g[i].nxt){ v=g[i].to; //如果已经在同一个环(花)中或者是白点(意为这已经有匹配点),只接跳过 //这种情况不会增加匹配数 if(getf(u)==getf(v)||vis[v]==2) continue; //如果没有被染色 if(!vis[v]) { //先染为白色,将前继点指向u vis[v]=2,pre[v]=u; //如果没有被匹配过,直接匹配成功 if(!match[v]){ //增广路取反 for(int x=v,last;x;x=last) last=match[pre[x]],match[x]=pre[x],match[pre[x]]=x; return 1; } //如果被匹配过,则把匹配v的点染为黑色,放入队列中 vis[match[v]]=1,q.push(match[v]); } //v是黑色,形成奇环,则缩点(开花)。 else { int lca=LCA(u,v); blossom(u,v,lca),blossom(v,u,lca); } } } return 0; } int main(){ while(~scanf("%d%d",&n,&m)) { Init(); for(int i=1;i<=n;i++){ scanf("%d",&dd[i]); for(int j=1;j<=dd[i];j++){ nodes[i][j-1]=++tot; } } for(int i=1;i<=m;i++){ scanf("%d%d",&u,&v); ++tot; for(int j=1;j<=dd[u];j++){ add(tot,nodes[u][j-1]),add(nodes[u][j-1],tot); } ++tot; for(int j=1;j<=dd[v];j++){ add(tot,nodes[v][j-1]),add(nodes[v][j-1],tot); } add(tot,tot-1); add(tot-1,tot); } n=tot; // cout<<n<<" "<<tot<<endl; for(int i=1;i<=n;i++) if(!match[i]&&aug(i)) ans++; // puts("!"); ll counter=0; for(int i=1;i<=n;i++){ if(match[i]) ++counter; } if(counter==tot)printf("Yes\n"); else printf("No\n"); // printf("%d\n",ans); // for(int i=1;i<=n;i++) // printf("%d%c",match[i]," \n"[i==n]); } return 0; }