#网络流,最大流,dinic#洛谷 3701 「伪模板」主席树

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sugar_free_mint/article/details/82788518

题目

关系图
给出一些敌对关系,主席的生命需加上膜法师的数量,每打斗一次减一条命,一共打m场,问一共能打赢多少场


分析

可以发现题目其实是求最大匹配,这样理解就比较容易了,样例解释图
样例解释


代码

    #include <cstdio>
    #include <vector>
    #include <queue>
    #define rr register
    #define r(i,a,b) for (rr int i=a;i<=b;i++)
    #define min(a,b) ((a)<(b))?(a):(b)
    using namespace std;
    struct node{
        int y,w,next;
    }e[10001];
    int a[101],b[101],c[101],d[101],ls[201],dis[201];
    vector<int>p[6]; int n,m,s,t,k=1,ans;
    inline int in(){
        rr int ans=0; rr char c=getchar();
        while (c<48||c>57) c=getchar();
        while (c>47&&c<58) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
        return ans;
    }
    inline int read(){
        rr char c=getchar(); rr int ans;
        while (c<65||c>90) c=getchar();
        if (c=='J') ans=1;
        if (c=='H') ans=2;
        if (c=='W') ans=3;
        if (c=='Y') ans=4;
        if (c=='E') ans=5;
        while (c>64&&c<91) c=getchar();
        return ans;
    }
    inline void add(int x,int y,int w){
        e[++k]=(node){y,w,ls[x]}; ls[x]=k;
        e[++k]=(node){x,0,ls[y]}; ls[y]=k;
    }
    inline bool bfs(int s){
        r(i,1,t) dis[i]=0;
        rr queue<int>q;
        q.push(s); dis[s]=1;
        while (q.size()){
            rr int x=q.front(); q.pop();
            for (rr int i=ls[x];i;i=e[i].next)
            if (e[i].w>0&&!dis[e[i].y]){
                dis[e[i].y]=dis[x]+1;
                if (e[i].y==t) return 1;
                q.push(e[i].y);
            }
        }
        return 0;
    }
    inline int dfs(int x,int now){
        if (x==t||!now) return now;
        rr int rest=0,f;
        for (rr int i=ls[x];i;i=e[i].next)
        if (e[i].w>0&&dis[e[i].y]==dis[x]+1){
            rest+=(f=dfs(e[i].y,min(now-rest,e[i].w)));
            e[i].w-=f; e[i^1].w+=f;
            if (now==rest) return rest;
        }
        if (!rest) dis[x]=0;
        return rest;
    }
    int main(){
        n=in(); rr int m=in(),cnt=0; s=n<<1|1; t=s+1;
        r(i,1,n) a[i]=read(); r(i,1,n) b[i]=read();
        r(i,1,n) c[i]=in(); r(i,1,n) d[i]=in();
        r(i,1,n) cnt+=a[i]==4; r(i,1,n) c[i]+=a[i]==1?cnt:0; cnt=0;
        r(i,1,n) cnt+=b[i]==4; r(i,1,n) d[i]+=b[i]==1?cnt:0;//主席加上膜法师的数量(补血)
        r(i,1,n) add(s,i,c[i]),add(i+n,t,d[i]);
        r(i,1,n) p[b[i]].push_back(i);
        r(i,1,n)//敌对关系建图
        if (a[i]==1){
            if (p[2].size()) r(j,0,p[2].size()-1) add(i,p[2][j]+n,1);
            if (p[3].size()) r(j,0,p[3].size()-1) add(i,p[3][j]+n,1);
        }
        else if (a[i]==2){
            if (p[3].size()) r(j,0,p[3].size()-1) add(i,p[3][j]+n,1);
            if (p[5].size()) r(j,0,p[5].size()-1) add(i,p[5][j]+n,1);
        }
        else if (a[i]==3){
            if (p[4].size()) r(j,0,p[4].size()-1) add(i,p[4][j]+n,1);
            if (p[5].size()) r(j,0,p[5].size()-1) add(i,p[5][j]+n,1);	
        }
        else if (a[i]==4){
            if (p[1].size()) r(j,0,p[1].size()-1) add(i,p[1][j]+n,1);
            if (p[2].size()) r(j,0,p[2].size()-1) add(i,p[2][j]+n,1);		
        }
        else if (a[i]==5){
            if (p[1].size()) r(j,0,p[1].size()-1) add(i,p[1][j]+n,1);
            if (p[4].size()) r(j,0,p[4].size()-1) add(i,p[4][j]+n,1);
        }
        while (bfs(s)){//最大流
            ans+=dfs(s,1e9);
            if (ans>m) return !printf("%d",m);
        }
        return !printf("%d",ans);
    }

猜你喜欢

转载自blog.csdn.net/sugar_free_mint/article/details/82788518