一般图最大匹配

转载:https://www.cnblogs.com/xiongtao/p/11189452.html

题意:有一个n个点,m条边的图  ,给出每个点的度数,问是否可以成为该图的子图。

样例:

n个点  m条边 每个点的度数

4 4
1 2
3 4
2 3
1 4
1
2
1
0

 

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<queue>
  6 #define inf 0x3f3f3f3f
  7 using namespace std;
  8 typedef long long ll;
  9 const int maxn=1050;
 10 bool g[maxn][maxn],inque[maxn],inpath[maxn];
 11 bool inhua[maxn];
 12 int st,ed,newbase,ans,n;
 13 int base[maxn],pre[maxn],match[maxn];
 14 int head,tail,que[maxn]; 
 15 int x[maxn],y[maxn],f[maxn],mp[maxn][maxn],ne,np;
 16 
 17 void Push(int u)
 18 {
 19     que[tail]=u;
 20     tail++;
 21     inque[u]=1;
 22 }
 23 int Pop()
 24 {
 25     int res=que[head];
 26     head++;
 27     return res;
 28 }
 29 
 30 int lca(int u,int v)//寻找公共花祖先 
 31 {
 32     memset(inpath,0,sizeof(inpath));
 33     while(1)
 34     {
 35         u=base[u];
 36         inpath[u]=1;
 37         if(u==st) break;
 38         u=pre[match[u]];    
 39     }    
 40     while(1)
 41     {
 42         v=base[v];
 43         if(inpath[v]) break;
 44         v=pre[match[v]];
 45     }
 46     return v;
 47 } 
 48 void reset(int u)//缩环 
 49 {
 50     int v;
 51     while(base[u]!=newbase)
 52     {
 53         v=match[u];
 54         inhua[base[u]]=inhua[base[v]]=1;
 55         u=pre[v];
 56         if(base[u]!=newbase) pre[u]=v;
 57     }
 58 } 
 59 void contract(int u,int v)//
 60 {
 61     newbase=lca(u,v);
 62     memset(inhua,0,sizeof(inhua));
 63     reset(u);
 64     reset(v);
 65     if(base[u]!=newbase) pre[u]=v;
 66     if(base[v]!=newbase) pre[v]=u;
 67     for(int i=1;i<=n;i++)
 68     {
 69         if(inhua[base[i]]){
 70             base[i]=newbase;
 71             if(!inque[i])
 72                 Push(i);
 73         }
 74     }
 75 }
 76 void findaug()
 77 {
 78     memset(inque,0,sizeof(inque));
 79     memset(pre,0,sizeof(pre));
 80     for(int i=1;i<=n;i++)//并查集 
 81         base[i]=i;
 82     head=tail=1;
 83     Push(st);
 84     ed=0;
 85     while(head<tail)
 86     {
 87         int u=Pop();
 88         for(int v=1;v<=n;v++)
 89         {
 90             if(g[u][v]&&(base[u]!=base[v])&&match[u]!=v)
 91             {
 92                 if(v==st||((match[v]>0) && pre[match[v]]>0))//成环 
 93                     contract(u,v);
 94                 else if(pre[v]==0)
 95                 {
 96                     pre[v]=u;
 97                     if(match[v]>0)
 98                         Push(match[v]);
 99                     else//找到增广路 
100                     {
101                         ed=v;
102                         return ;    
103                     }    
104                 }
105             }
106         }
107     }
108 }
109 void aug()
110 {
111     int u,v,w;
112     u=ed;
113     while(u>0)
114     {
115         v=pre[u];
116         w=match[v];
117         match[v]=u;
118         match[u]=v;
119         u=w;
120     }
121 }
122 void edmonds()//匹配 
123 {
124     memset(match,0,sizeof(match));
125     for(int u=1;u<=n;u++)
126     {
127         if(match[u]==0)
128         {
129             st=u;
130             findaug();//以st开始寻找增广路 
131             if(ed>0) aug();//找到增广路  重新染色,反向 
132         }
133     }
134 }
135 //以上是带花树求最大匹配算法  不用看 
136  
137 void create()//建图 
138 {
139     n=0;
140     memset(g,0,sizeof(g));
141     for(int i=1;i<=np;i++)
142         for(int j=1;j<=f[i];j++)
143             mp[i][j]=++n;//拆点,给每个度的点编号 
144     for(int i=0;i<ne;i++)
145     {//此时n+1代表x,n+2代表y 
146         for(int j=1;j<=f[x[i]];j++)
147             g[mp[x[i]][j]][n+1]=g[n+1][mp[x[i]][j]]=1;//每个度的点与对应的x,y相连 
148         for(int j=1;j<=f[y[i]];j++)
149             g[mp[y[i]][j]][n+2]=g[n+2][mp[y[i]][j]]=1;
150         g[n+1][n+2]=g[n+2][n+1]=1;//x与y相连 
151         n+=2;
152     }    
153 }
154 void print()
155 {
156     ans=0;
157     for(int i=1;i<=n;i++)
158         if(match[i]!=0)
159         {
160             ans++;
161 //            if(match[i]>i)
162 //            cout<<"_____"<<i<<' '<<match[i]<<endl;
163         }
164     //cout<<"******"<<ans<<' '<<n<<endl;
165     if(ans==n)    printf("YES\n");
166     else    printf("NO\n");
167 }
168 int main()
169 {
170 
171     //np点数   ne边数
172     while(~scanf("%d%d", &np, &ne))
173     {
174         //f[i]每个点的度数
175         for(int i=1;i<=np;i++)
176             scanf("%d",&f[i]);
177         //存边
178         for(int i=0;i<ne;i++)
179             scanf("%d%d",&x[i],&y[i]);
180 
181         create(); //建图
182         edmonds(); //匹配
183         print();    //打印答案
184     }     
185     return 0;
186 }

 

posted @ 2020-07-17 17:22  SummerMingQAQ  阅读(202)  评论(0编辑  收藏  举报