Gym 102419H In-degree 費用流or最大匹配

題目鏈接: http://codeforces.com/gym/102419/problem/H

題意:

2000個點,2000條邊,無重邊無自環的無向圖,現在要你把這些無向邊變成有向邊,使得每個點的入度爲給你的數組 AA ,如果爲 1-1 則任意入度即可。

做法:

兩種做法,第一種是費用流做法, 1n1-n 表示點, 1m1-m 表示邊,我們將邊也看成點,從原點到所有點連一條邊,如果這個 aa 不爲 1-1 則連接邊流量爲 a[i]a[i] ,費用爲 1-1 ,否則就是 (m,0)(m,0) ,這樣的話就可以優先跑需要的點,並且度爲無限的點不會干擾到最後結果。然後驗證一下對不對就行了。

還有一種最大匹配做法,二分圖,把邊當成點,做匈牙利匹配即可,代碼不是自己寫的就不貼了。

代碼

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=4005;
const int maxm=80005;
const int inf=0x3f3f3f3f;
int dis[maxn],a[maxn],u[maxn],v[maxn];
int vis[maxn],pre[maxn];
int head[maxn],cnt,ed[maxm];
int n,m,sp,tp;
ll ans=0;
struct node{
    int to,cap,cost,next;
}e[maxm];
void add(int from,int to,int cap,int cost){
    e[cnt].to=to; e[cnt].cap=cap;
    e[cnt].cost=cost; e[cnt].next=head[from];
    head[from]=cnt++;

    e[cnt].to=from; e[cnt].cap=0;
    e[cnt].cost=-cost; e[cnt].next=head[to];
    head[to]=cnt++;
}
bool spfa(int s,int t,int &flow,int &cost){
    queue<int> q;
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    dis[s]=0;  q.push(s);
    vis[s]=1;
    int d=inf;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(e[i].cap>0&&dis[v]>dis[u]+e[i].cost){
                dis[v]=dis[u]+e[i].cost;
                pre[v]=i;
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    if(dis[t]==inf){
        return false;
    }
    for(int i=pre[t];~i;i=pre[e[i^1].to]){
        d=min(d,e[i].cap);
    }
    for(int i=pre[t];~i;i=pre[e[i^1].to]){
        e[i].cap-=d;
        e[i^1].cap+=d;
        cost+=e[i].cost*d;
    }
    flow+=d;
    return true;
}
pii mcmf(int s,int t){
    int flow=0,cost=0;
    while(spfa(s,t,flow,cost)){
        //cout<<flow<<" "<<cost<<endl;
    }
    return {flow,cost};
}
int main(){
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    sp=0;tp=n+m+1;
    int sum=0;
    rep(i,1,n){
        int x; scanf("%d",&x);
        if(x!=-1) add(sp,i,x,-1),sum+=x;
        else add(sp,i,m,0);

    }
    rep(i,1,m){
        add(n+i,tp,1,0);
        scanf("%d%d",&u[i],&v[i]);
        ed[i]=cnt;
        add(u[i],i+n,1,0);
        add(v[i],i+n,1,0);
    }
    pii ret=mcmf(sp,tp);
    if(ret.first==m&&ret.second==-sum){
        printf("YES\n");
        rep(i,1,m){
            if(e[ed[i]].cap==1) printf("%d %d\n",u[i],v[i]);
            else printf("%d %d\n",v[i],u[i]);
        }
    }
    else printf("NO\n");
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章