• Wpremig和Jhadgre的藏宝图(最大流+二分)


    Wpremig和Jhadgre的藏宝图

    题目链接:https://ac.nowcoder.com/acm/contest/333/M

    Description:

    Jhadgre在生日那天收到了一张神秘的藏宝图,于是他决定和Wpremig分享这张藏宝图,并且去寻宝!

    这张藏宝图上总共有N行,每行有M个格子,共N*M个格子,每个格子上写了一个数字。

    藏宝图上写了一段字:神秘的有缘人啊,这些格子已经被其他人挖过了,我已经替你标出了所有格子被挖到的深度,并且在这个宝藏上加了一个魔法,只要你把所有格子都挖到同一个深度,宝藏自然就会出现。

    这看似是一个很简单的问题,只要知道现在最深的那个格子,其他格子都挖到这个深度,就是最快的方式了。然而Wpremig和Jhadgre却发现,还有一句话:我知道你们有两个人,所以你们在挖的时候必须两个人同时各挖一个格子,并且这两个格子必须相邻!

    这就比较尴尬了,Wpremig和Jhadgre很不高兴,这是送礼呢还是膈应人呢?不挖了!

    虽然这样说,但是人总是会遵循“真香定理”。在几天后Wpremig和Jhadgre还是决定去挖宝藏,现在他们在出发前想知道,最少需要挖多少次才能获得宝藏呢?(假设每次一个人挖一个格子可以将这个格子的深度+1)

    Input:

    第一行一个整数T表示数据组数(T<=10)
    对于每组数据,第一行两个整数N,M。
    接下去N行每行M个整数。
    保证 T<=10,1<=N,M<=40,所有数为正整数且小于1000000000

    Output:

    对于每组数据输出最少的挖掘次数,若无论如何都不能获得宝藏,则输出-1;

    Sample Input:

    1
    2 2 
    1 2 
    2 3

    Sample Output:

    2

    题解:

    这里挖格子必须两个相邻的格子一起挖,我们发现二分图也是相邻的格子在两边,那么我们就可以首先将图进行黑白染色,之后令黑在左,白在右进行构图。

    每一个黑格子肯定连向与它相邻的白格子,现在来确定容量。

    我们假定最后的深度为x,设黑色格子数量为black,白色格子数量为white,黑色格子目前的数量和为sumblack,白色格子的数量和为sumwhile,那么最后的状态就有:

    black*x-sumblack = white*x-sumwhite,最后有(black-white)*x = sumblack-sumwhite。

    当black=white时,首先要有两个sum相等,然后就可以check求出x最优值;如果black!=white,我们可以将x接出来,然后checkx看是否合法。

    对于check就是边容量的问题,这里的x是最大深度,那么我们与源点以及汇点连接的边权就为x减去目前深度就好了。

    我一开始就是想直接checkx,但是发现黑白格子数量会影响到x的取值= =

    代码如下:

    #include <bits/stdc++.h>
    #define s 0
    #define t 1700
    #define INF 1e18
    using namespace std;
    typedef long long ll;
    const int N = 45,M = 45;
    int T,n,m,tot,mx;
    ll sum1,sum2;
    ll head[1705],d[1705],cnt[4];
    int a[N][M],color[N][M];
    int dx[5]={1,0,0,-1};
    int dy[5]={0,1,-1,0};
    struct Edge{
        ll c;
        int v,next;
    }e[10010];
    void adde(int u,int v,ll c){
        e[tot].v=v;e[tot].next=head[u];e[tot].c=c;head[u]=tot++;
        e[tot].v=u;e[tot].next=head[v];e[tot].c=0;head[v]=tot++;
    }
    bool ok(int x,int y){
        return x>=1 && x<=n && y>=1 && y<=m;
    }
    bool bfs(int S,int T){
        memset(d,0,sizeof(d));d[S]=1;
        queue <ll > q;q.push(S);
        while(!q.empty()){
            ll u=q.front();q.pop();
            for(int i=head[u];i!=-1;i=e[i].next){
                int v=e[i].v;
                if(!d[v] && e[i].c>0){
                    d[v]=d[u]+1;
                    q.push(v);
                }
            }
        }
        return d[T]!=0;
    }
    ll dfs(int S,ll A){
        ll flow=0,f;
        if(S==t || A==0) return A;
        for(ll i=head[S];i!=-1;i=e[i].next){
            ll v=e[i].v;
            if(d[v]!=d[S]+1) continue ;
            f=dfs(v,min(A,e[i].c));
            if(f){
                e[i].c-=f;
                e[i^1].c+=f;
                flow+=f;
                A-=f;
                if(A==0) break;
            }
        }
        if(!flow) d[S]=-1;
        return flow;
    }
    ll Dinic(){
        ll max_flow=0;
        while(bfs(0,t)){
            max_flow+=dfs(0,INF);
        }
        return max_flow;
    }
    void build(ll x){
        tot=0;memset(head,-1,sizeof(head));
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(color[i][j]==1) adde(s,(i-1)*m+j,x-a[i][j]);
                else adde((i-1)*m+j,t,x-a[i][j]);
                if(color[i][j]==2) continue ;
                for(int k=0;k<4;k++){
                    int nowx = i+dx[k],nowy = j+dy[k];
                    if(ok(nowx,nowy)) adde((i-1)*m+j,(nowx-1)*m+nowy,INF);
                }
            }
        }
    }
    void dfs_col(int x,int y,int col){
        color[x][y]=col;
        cnt[col]++;
        if(col==1) sum1+=a[x][y];
        if(col==2) sum2+=a[x][y];
        for(int i=0;i<4;i++){
            ll nowx = x+dx[i],nowy = y+dy[i];
            if(ok(nowx,nowy)&&!color[nowx][nowy]) dfs_col(nowx,nowy,3-col);
        }
    }
    int check(ll x){
        build(x);
        ll flow = Dinic();
        for(int i=head[s];i!=-1;i=e[i].next) if(e[i].c) return 0;
        return 1;
    }
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&n,&m);
            mx = 0;
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++){
                    scanf("%d",&a[i][j]);
                    mx=max(a[i][j],mx);
                }
            }
            memset(color,0,sizeof(color));
            memset(cnt,0,sizeof(cnt));
            sum1 = sum2 = 0;
            dfs_col(1,1,1);
            if((n*m)%2==0){
                if(sum1!=sum2){
                    printf("-1
    ");
                    continue ;
                }
                ll l=mx,r=1e13,mid;
                while(l<r){
                    mid=l+r>>1;
                    if(check(mid)) r=mid;
                    else l=mid+1;
                }
                if(l==1e13) printf("-1
    ");
                else printf("%lld
    ",(l*m*n-sum1-sum2)/2);
            }else{
                ll x = (sum1-sum2)/(cnt[1]-cnt[2]);
                if(check(x)) printf("%lld
    ",(x*m*n-sum1-sum2)/2);
                else printf("-1
    ");;
            }
        }
        return 0;
    }
  • 相关阅读:
    System.Xml.XmlException: There is no Unicode byte order mark. Cannot switch to Unicode.
    ClientSide Cookie Management optanoncategoryC0004
    How is OAuth 2 different from OAuth 1?
    Why OAuth 1.0a?
    Converting PKCS#12 certificate into PEM using OpenSSL
    OneTrust Cookie AutoBlocking™
    Ruby on rails开发从头来(windows)(二十二)测试Controller
    Ruby on rails开发从头来(windows)(十九)测试开始
    Ruby on rails开发从头来(windows)(十五)添加用户
    Ruby on rails开发从头来(windows)(十六)登录
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/10230058.html
Copyright © 2020-2023  润新知