Description
给定无向图 (n le 50, m le 100),求能否选出一些边使得第 (i) 个顶点恰好与 (d_i (1 le d_i le 2)) 条边相连。
Solution (!Fake)
(以下算法已被 hack,谨慎参考!)
最大流
原图结点 (i) 对应 (i,i'),边 (<a_i,b_i>) 对应 (a_i o b_i',b_i o a_i'),那么这条边被选中,对应的两条边都产生了流
(S o i, i' o T),容量各为 (d_i)
最后检查与最大流是否为 (sum d_i) 即可
#include <bits/stdc++.h>
using namespace std;
const int maxn=50005;
const int maxm=500005;
const int inf=0x3f3f3f3f;
struct Node{
int to,val,next;
}q[maxm<<1];
int head[maxn],cnt=0,dep[maxn],cur[maxn],vis[maxn];
int sp,ep,maxflow;
void init(){
memset(head,-1,sizeof(head));
cnt=2,maxflow=0;
}
void addedge(int from,int to,int val){
q[cnt].to=to;
q[cnt].val=val;
q[cnt].next=head[from];
head[from]=cnt++;
}
void make(int from,int to,int val){
addedge(from,to,val);
addedge(to,from,0);
}
bool bfs(int n){
for(int i=0;i<=n;i++){
cur[i]=head[i],dep[i]=0x3f3f3f3f;
vis[i]=0;
}
dep[sp]=0;
queue<int>que;
que.push(sp);
while(!que.empty()){
int x=que.front();
que.pop();
vis[x]=0;
for(int i=head[x];i!=-1;i=q[i].next){
int to=q[i].to;
if(dep[to]>dep[x]+1&&q[i].val){
dep[to]=dep[x]+1;
if(!vis[to]){
que.push(to);
vis[to]=1;
}
}
}
}
if(dep[ep]!=inf) return true;
else return false;
}
int dfs(int x,int flow){
int rlow=0;
if(x==ep){
maxflow+=flow;
return flow;
}
int used=0;
for(int i=cur[x];i!=-1;i=q[i].next){
cur[x]=i;
int to=q[i].to;
if(q[i].val&&dep[to]==dep[x]+1){
if(rlow=dfs(to,min(flow-used,q[i].val))){
used+=rlow;
q[i].val-=rlow;
q[i^1].val+=rlow;
if(used==flow) break;
}
}
}
return used;
}
int dinic(int n){
while(bfs(n)){
dfs(sp,inf);
}
return maxflow;
}
signed main()
{
int n,m;
while(cin>>n>>m)
{
init();
int d[105];
int sum=0;
for(int i=1;i<=n;i++) cin>>d[i], sum+=d[i];
int t1,t2;
for(int i=1;i<=n;i++) make(2*n+1,i,d[i]), make(i+n,2*n+2,d[i]);
for(int i=1;i<=m;i++)
{
cin>>t1>>t2;
make(t1,t2+n,1);
make(t2,t1+n,1);
}
sp=2*n+1;
ep=2*n+2;
cout<<(dinic(2*n+2)==sum ? "Yes" : "No")<<endl;
}
}