2020牛客暑期多校训练营(第一场)I.1 or 2
题目链接:https://ac.nowcoder.com/acm/contest/5666/I
题意:给你一个n个点m条边的无向图,通过删除一些边使每个点的度数满足di,若存在则输出Yes,否则输出No。
通过拆点来跑一般图的最大匹配,将度数为2的点进行拆点,拆完的点连向对应的x,y点。如果达到完美匹配,这条边的另一头必定匹配着另一个点的一个度,表示拆点原点相连,这样一条边的匹配是合乎要求的。
思路来源:https://www.cnblogs.com/xiongtao/p/11189452.html
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1050;
bool g[maxn][maxn],inque[maxn],inpath[maxn];
bool inhua[maxn];
int st,ed,newbase,ans,n;
int base[maxn],pre[maxn],match[maxn];
int head,tail,que[maxn];
int x[maxn],y[maxn],f[maxn],mp[maxn][maxn],ne,np;
void Push(int u){
que[tail]=u;
tail++;
inque[u]=1;
}
int Pop(){
int res=que[head];
head++;
return res;
}
int lca(int u,int v){
memset(inpath,0,sizeof(inpath));
while(1){
u=base[u];
inpath[u]=1;
if(u==st) break;
u=pre[match[u]];
}
while(1){
v=base[v];
if(inpath[v]) break;
v=pre[match[v]];
}
return v;
}
void reset(int u){
int v;
while(base[u]!=newbase){
v=match[u];
inhua[base[u]]=inhua[base[v]]=1;
u=pre[v];
if(base[u]!=newbase) pre[u]=v;
}
}
void contract(int u,int v){
newbase=lca(u,v);
memset(inhua,0,sizeof(inhua));
reset(u);
reset(v);
if(base[u]!=newbase) pre[u]=v;
if(base[v]!=newbase) pre[v]=u;
for(int i=1;i<=n;i++){
if(inhua[base[i]]){
base[i]=newbase;
if(!inque[i])
Push(i);
}
}
}
void findaug(){
memset(inque,0,sizeof(inque));
memset(pre,0,sizeof(pre));
for(int i=1;i<=n;i++)
base[i]=i;
head=tail=1;
Push(st);
ed=0;
while(head<tail){
int u=Pop();
for(int v=1;v<=n;v++){
if(g[u][v]&&(base[u]!=base[v])&&match[u]!=v){
if(v==st||(match[v]>0)&&pre[match[v]]>0)
contract(u,v);
else if(pre[v]==0){
pre[v]=u;
if(match[v]>0)
Push(match[v]);
else{
ed=v;
return ;
}
}
}
}
}
}
void aug(){
int u,v,w;
u=ed;
while(u>0){
v=pre[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){
st=u;
findaug();
if(ed>0)aug();
}
}
}
void create(){
n=0;
memset(g,0,sizeof(g));
for(int i=1;i<=np;i++)
for(int j=1;j<=f[i];j++)
mp[i][j]=++n;
for(int i=0;i<ne;i++){
for(int j=1;j<=f[x[i]];j++)
g[mp[x[i]][j]][n+1]=g[n+1][mp[x[i]][j]]=1;
for(int j=1;j<=f[y[i]];j++)
g[mp[y[i]][j]][n+2]=g[n+2][mp[y[i]][j]]=1;
g[n+1][n+2]=g[n+2][n+1]=1;
n+=2;
}
}
void print(){
ans=0;
for(int i=1;i<=n;i++)
if(match[i]!=0)
ans++;
if(ans==n) printf("Yes\n");
else printf("No\n");
}
int main(){
int t,k=0;
while(~scanf("%d%d",&np,&ne)){
for(int i=1;i<=np;i++)
scanf("%d",&f[i]);
for(int i=0;i<ne;i++)
scanf("%d%d",&x[i],&y[i]);
create();
edmonds();
print();
}
}