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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章