题目链接:https://ac.nowcoder.com/acm/contest/5666/I
解题思路:标准的是一般图的最大匹配,但是没有学过,就只能用网络流来求解,我们可以将一个点分成两个点,具体为
i和i+n两个点,同时从源点向i连接流量为di的边,从i+n向汇点连接权值为dii的边,对于一条边的两个顶点U和V,分别连接U和V+N以及
V和U+N,这样如果最后的最大流为di的和则就是YES,在求解过程中,每增大一个流量,相当于选择一条边,那么这条边的反向边同样也可以选择,
这时候就相当于U和V的这条边纳入最后,同时U的Di和V的Di都进行了减一操作。
#include <bits/stdc++.h> using namespace std; const int maxn=1e6+10; const int inf = 0x3f3f3f; struct no { int next; int to; int val; }edge[maxn]; int cnt; int head[maxn]; int belong[maxn]; int dep[maxn]; int a[maxn]; int n,m,s,t; void add(int u,int v,int w) { edge[cnt].to=v,edge[cnt].val=w,edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].to=u,edge[cnt].val=0,edge[cnt].next=head[v]; head[v]=cnt++; } bool bfs() { memset(dep,0,sizeof(dep)); dep[s]=1; queue<int>q; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(!dep[v]&&edge[i].val>0) { dep[v]=dep[u]+1; q.push(v); } } } return dep[t]; } int dfs(int u,int maxflow) { int tempflow; if(u==t) { return maxflow; } int add=0; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(dep[v]==dep[u]+1&&edge[i].val>0&&(tempflow=dfs(v,min(maxflow-add,edge[i].val)))) { edge[i].val-=tempflow; edge[i^1].val+=tempflow; add+=tempflow; if(maxflow==add) break; } } return add; } int dicnic() { int ans=0; while(bfs()) { int temp; while(temp=dfs(s,inf)) ans+=temp; } return ans; } void init() { memset(head,-1, sizeof(head)); cnt=0; s=0,t=2*n+1; } int main() { while(~scanf("%d%d",&n,&m)) { int sum=0; init(); int odd = 0; for(int i=1;i<=n;i++) { int a; cin>>a; add(s,i,a); add(i+n,t,a); sum+=a; odd += (a==1); } for(int i=1;i<=m;i++) { int a,b; cin>>a>>b; add(a,b+n,1); add(b,a+n,1); } if(odd%2==1) { printf("No "); continue; } int ans = dicnic(); if(ans==sum) { printf("Yes "); } else{ printf("No "); } } return 0; }