Codeforces Round #227 (Div. 2) George and Interesting Graph

题意:有向图500个点,1000条边,删除和添加一些边使得除了一个点以外每个点的入度和出度为2,剩下那一个点跟所有点都有连边,问最小操作数。
思路:枚举中心点,然后将剩下的点拆成2个点,入度和出度(精神分裂)。然后二分图跑最大匹配,这样就好搞了。
代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int maxn = 505;
const int inf = 2e9+5;
int head[maxn],mat[maxn],n,m,tot;
bool vis[maxn];
struct edge{
    int v,nex;
}e[maxn<<1];
void add(int u,int v){
    e[++tot] = {v,head[u]},head[u] = tot;
}
vector<int>g[maxn];
bool find(int u){
    for(auto &v:g[u])if(!vis[v]){
        vis[v] = 1;
        if(!mat[v]||find(mat[v])) {
            mat[v] = u;
            return 1;
        }
    }
    return 0;
}
int main(){
    IO;cin>>n>>m;
    forn(i,m){
        int u,v;cin>>u>>v;
        add(u,v);
    }
    int ans = inf;
    for1(cen,n){
        for1(i,maxn-5) g[i].clear(),mat[i] = 0;
        int in = 0,out = 0,cnt = 0,res = 0;
        bool ok = 0;
        for1(u,n){
            if(u==cen){
                for(int i = head[u];i;i = e[i].nex){
                    int v = e[i].v;
                    out++;
                    if(v==u) ok = 1;
                }
            }else{
                for(int i = head[u];i;i = e[i].nex){
                    int v = e[i].v;
                    if(v==cen){
                        in++;
                        continue;
                    }
                    g[u].push_back(v);
                }
            }    
        }
        if(ok) out--;
        res+=(n-1)*2-in-out;
        for1(i,n)if(!g[i].empty()){
            for1(i,maxn-5) vis[i] = 0;
            if(find(i)) cnt++;
        }
        if(ok) out++;
        else res++;
        res += m-in-out-cnt;
        res += n-1-cnt;
        ans = min(ans,res);
    }
    cout << ans <<'\n';
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章