予鈴

アウトプットとメモ書きの中間みたいな記事がたくさん出ます。

D - 浮気予防

問題

atcoder.jp

考えていたこと

 Pを問題文中での悪い虫の頂点集合、v_{0}を高橋くんとする。
Pを含む部分グラフとv_{0}を含む部分グラフに分ける最小カットを考えればいいことがわかる。
Pの要素をすべてsinkに置き換えて最大流を流す → ”ログインできなくなる”という操作が再現できない。(具体的には、sample3が3になる)

正解

・やっぱり最小カット。Psinkをつなぐpathを仮定して最大流を流せば良い。
・よく考えると、”ログインできなくさせる”という操作はp \in Pにだけ行えば良い。
p_{i}からsinkへのpathをカットすると、p_{i}をログインさせなくなるという操作が実現できる。
・問題をよく読むと頂点を削除することができないですねこれ…ずっとできるものだと思ってた。


解答

最小カット久々に使いました。

#include<bits/stdc++.h>
using ll  = long long;
using namespace std;
#define int ll
#define rep(i,n) for(int i=0;i<n;i++)
#define INF (sizeof(int) == 4 ? (int)1e9:(int)1e18)
struct Edge{int to,cap,rev;};
class Dinic{//max flow
public:
    int n;
    vector<vector<Edge> >G;
    vector<int> level,iter;
    Dinic(int size): n(size),G(vector<vector<Edge>>(n)){};
    void add_Edge(int from, int to, int cap){
        Edge q={to,cap,int(G[to].size())};
        G[from].emplace_back(q);
        q={from,0,int(G[from].size()-1)};
        G[to].emplace_back(q);
    }
    void bfs(int s){
        level=vector<int>(n,-1);
        queue<int>q;
        level[s]=0;
        q.push(s);
        while(!q.empty()){
            int v=q.front();q.pop();
            for(auto &e :G[v]){
                if(e.cap>0&&level[e.to]<0){
                    level[e.to]=level[v]+1;
                    q.push(e.to);
                }
            }
        }
    }
    function<int(int,int,int)>dfs = [&](int v, int t, int f) -> int{
        if(v==t)return f;
        for(;iter[v]<G[v].size();iter[v]++){
            Edge &e=G[v][iter[v]];
            if(level[v]>=level[e.to]||e.cap<=0) continue;
            int d =dfs(e.to,t,min(f,e.cap));
            if(d>0){
                e.cap-=d;
                G[e.to][e.rev].cap+=d;
                return d;
            }
        }
        return 0;
    };
    int max_flow(int s,int t) {//from s to t,ford_fulkerson
        int flow=0;
        while(1){
            bfs(s);
            if(level[t]<0)return flow;
            iter=vector<int>(n);
            int f;
            while((f=dfs(s,t,INF))>0)flow+=f;
        }
    };
};
signed main(){
    int N,G,E;
    cin >> N >> G >> E;
    vector<int>p(G);
    for(auto & g : p) cin >> g;
    auto fl = Dinic(N+1);
    int sink = N;
    rep(_,E){
        int a,b; cin >> a >> b;
        fl.add_Edge(a,b,1);
        fl.add_Edge(b,a,1);
    }
    for(auto e : p)fl.add_Edge(e, sink,1);
    cout << fl.max_flow(0,sink) << endl;
}