2020牛客暑期多校训练营(第一场)I

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;
    }
}