Educational Codeforces Round 43 (Rated for Div. 2)题解

ABC 喵喵喵

D

数学归纳吖!

  • n=0 ok
  • n=1 ok 形成d[1]+1个点的完全图
  • n>2 一定能到达比n更小的状态
    d[n],d[n-1]....d[1] -> d[n-1]-d[1],d[n-2]-d[1],...d[2]-d[1]

E

  • 不考虑A操作,只考虑B操作:排序+贪心。
  • 考虑A操作,会发现a全部加到一个人身上是最好的。
  • 枚举把a加到哪个人头上。

F

  • 二分图的最小边覆盖 = V - MaxMatch
  • 最大匹配前是个负号哎!那没有被最大流浸泡过的边会不会就是答案呢?
  • Hint:源点向左集连容量为deg-k的边

code

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <vector>

using namespace std;
const int N = 5000 + 10;  
const int INF = 1e9 + 7;  
#define mp(x,y) make_pair(x,y)
  
struct Edge {  
    int from , to , cap , flow, id;  
};  
bool visit[N];
struct Dinic {   
    int n,m,s,t;  
    vector<Edge> edges;  
    vector<int> f[N];  
    bool vis[N];  
    int d[N];  
    int cur[N];   
    void init(int n) {
        this->n = n;
        edges.clear();
        for (int i = 0; i < N; i ++) f[i].clear();
        memset(d, 0, sizeof(d));
        memset(cur, 0, sizeof(cur));
        memset(visit, 0, sizeof(visit));
    }
    void AddEdge(int from,int to,int cap,int id)  
    {  
        edges.push_back((Edge){from,to,cap,0,id});  
        edges.push_back((Edge){to,from,0,0,id});  
        m = edges.size();  
        f[from].push_back(m-2);  
        f[to].push_back(m-1);  
    }  
    bool BFS()   
    {  
        memset(vis,0,sizeof(vis));  
        queue<int> q;  
        q.push(s);  
        d[s] = 0;  
        vis[s] = 1;     
        while(!q.empty())  
        {  
            int x = q.front(); q.pop();  
            for(int i=0;i<f[x].size();i++)  
            {  
                Edge &e = edges[f[x][i]];  
                //cout<<"to="<<e.to<<"from="<<e.from<<' '<<e.flow<<' '<<e.cap<<' '<<vis[e.to]<<endl;  
                if(!vis[e.to] && e.flow < e.cap) //只考虑残留网络中的弧   
                {  
                    vis[e.to] = 1;  
                    d[e.to] = d[x] + 1;//层次图  
                    q.push(e.to);   
                }  
            }  
        }  
        return vis[t];//能否到汇点,不能就结束   
    }  
    int DFS(int x,int a)//x为当前节点,a为当前最小残量   
    {  
        if(x == t || a == 0) return a;  
        int flow = 0 , r;  
          
        for(int& i = cur[x];i < f[x].size();i++)  
        {  
            Edge& e = edges[f[x][i]];  
            if(d[x] + 1 == d[e.to] && (r = DFS(e.to , min(a,e.cap - e.flow) ) ) > 0 )  
            {  
                e.flow += r;  
                edges[f[x][i] ^ 1].flow -= r;  
                //get Ans
                //printf("miao: %d\n", edges[f[x][i] ^ 1].id);
                //visit[edges[f[x][i] ^ 1].id] = 1;

                flow += r;//累加流量   
                a -= r;  
                if(a == 0) break;  
            }  
        }  
        return flow;  
    }  
    int MaxFlow(int s,int t)  
    {  
        this->s = s; this->t = t;  
        int flow = 0;  
        while(BFS())  
        {      
            memset(cur,0,sizeof(cur));  
            flow += DFS(s,INF);  
            //printf("%d\n", flow);
        }  
        for (int i=0;i<edges.size();i++) {
            if (edges[i].flow) visit[edges[i].id] = 1;
        }
        return flow;  
    }  
} G;

int n1,n2,m,deg[N];
vector< pair<int, int> > v[N];

void build_gragh(int k) {
    int S = n1+n2+1, T=n1+n2+2;
    G.init(T+2);
    for(int i=1;i<=n1;i++) {
        G.AddEdge(S,i,deg[i]-k,0);
    }
    for(int i=1;i<=n2;i++) {
        G.AddEdge(i+n1,T,deg[i+n1]-k,0);
    }
    for(int i=1;i<=n1;i++) {
        for (int j=0;j<v[i].size();j++) {
            G.AddEdge(i,v[i][j].first+n1,1,v[i][j].second);
        }
    }
    int ret = G.MaxFlow(S,T);

    printf("%d ", m-ret);
    for (int i=1;i<=m;i++) {
        if (visit[i] == 0) 
            printf("%d ", i);
    }
    printf("\n");
}

int main() {
    scanf("%d%d%d",&n1,&n2,&m);
    for(int i=1;i<=m;i++) {
        int x, y; 
        scanf("%d%d",&x,&y);
        v[x].push_back(mp(y, i));
        deg[x] ++, deg[n1+y]++;
    }
    printf("0\n");
    int mnDegree = *min_element(deg+1,deg+1+n1+n2);
    for (int i = 1; i <= mnDegree; i ++) {
        build_gragh(i);
    }
}

转载于:https://www.cnblogs.com/RUSH-D-CAT/p/9009556.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值