转载: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 "); 166 else printf("NO "); 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 }