[BZOJ2756][SCOI2012]奇怪的遊戲

如果我們知道了要變成的數d ,怎麼檢驗這個答案可不可行。
將整張棋盤黑白染色,黑點連向四邊的白點,容量爲無窮大,源點連向黑點,容量爲dv[i] ,白點連向匯點,容量爲dv[i] ,最後檢查是否滿流。
那麼當mn 爲偶數時,可以二分答案。
奇數時,不妨設黑格子比白格子多一個,不管怎麼操作,黑格子的和與白格子的和的差是定值,設爲dif ,再設最後變成的數爲d ,有:
(num+1)×dnum×d=dif
d=dif ,網絡流驗證即可。

#include<ctime>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<cassert>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<climits>
#define X first
#define Y second
#define DB double
#define lc now<<1
#define rc now<<1|1
#define MP make_pair
#define LL long long
#define pb push_back
#define sqr(_) ((_)*(_))
#define INF 0x3f3f3f3f
#define pii pair<int,int>
#define pdd pair<DB,DB>
#define ull unsigned LL
#define int LL
#define DEBUG(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
const int MAXN=44;
int ans=0,n,m,T,w[MAXN][MAXN],d,s1,s2,id[MAXN][MAXN],tot=0,color[MAXN][MAXN],_w[MAXN*MAXN];
struct Edge{
    int u,v,cap,flow;
    Edge(int u=0,int v=0,int cap=0,int flow=0):u(u),v(v),cap(cap),flow(flow){}
};
struct Dinic
{
    int S,T;
    vector<int> G[MAXN*MAXN];
    vector<Edge> edges;
    bool vis[MAXN*MAXN];
    int dis[MAXN*MAXN],cur[MAXN*MAXN];
    void init()
    {
        for(int i=0;i<MAXN*MAXN;i++)
            G[i].clear();
        edges.clear();
    }
    void add(int a,int b,int w)
    {
        edges.pb(Edge(a,b,w,0));
        edges.pb(Edge(b,a,0,0));
        int k=edges.size();
        G[a].pb(k-2);
        G[b].pb(k-1);
    }
    bool BFS()
    {
        memset(vis,0,sizeof(vis));
        queue<int> q;
        q.push(S);
        vis[S]=1;
        memset(dis,INF,sizeof(dis));
        dis[S]=0;
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=0;i<G[u].size();i++)
            {
                Edge& e=edges[G[u][i]];
                if(!vis[e.v]&&e.cap>e.flow)
                {
                    vis[e.v]=1;
                    dis[e.v]=dis[u]+1;
                    q.push(e.v);
                }
            }
        }
        return vis[T];
    }
    int DFS(int u,int a)
    {
        if(u==T||a==0)return a;
        int f=0,flow=0;
        for(int& i=cur[u];i<G[u].size();i++)
        {
            Edge& e=edges[G[u][i]];
            if(dis[e.v]==dis[u]+1&&((f=DFS(e.v,min(a,e.cap-e.flow)))>0))
            {
                flow+=f;
                e.flow+=f;
                edges[G[u][i]^1].flow-=f;
                a-=f;
                if(a==0)break;
            }
        }
        return flow;
    }
    int MaxFlow()
    {
        int res=0;
        while(BFS())
        {
            memset(cur,0,sizeof(cur));
            res+=DFS(S,LONG_LONG_MAX/10);
        }
        return res;
    }
    bool rebuild(int mid)
    {
        for(int i=0;i<edges.size();i++)
        {
            Edge& e=edges[i];
            e.flow=0;
            if(e.v==T)
            {
                e.cap=mid-_w[e.u];
                if(e.cap<0)return 0;
            }
            else if(e.u==S)
            {
                e.cap=mid-_w[e.v];
                if(e.cap<0)return 0;
            }
        }
        return 1;
    }
    bool check(int mid)
    {
        if(!rebuild(mid))return 0;
        ans=MaxFlow();
        for(int i=0;i<edges.size();i++)
        {
            //DEBUG("%I64d %I64d %I64d %I64d\n",edges[i].u,edges[i].v,edges[i].cap,edges[i].flow);
            if(edges[i].v==T&&edges[i].cap!=edges[i].flow)
                return 0;
        }
        return 1;   
    }
}Graph;
void colored()
{
    for(int i=1;i<=n;i++)
    {
        if(i&1)
        {
            for(int j=1;j<=m;j++)
                if(j&1)
                    color[i][j]=1;
        }
        else
        {
            for(int j=1;j<=m;j++)
                if(!(j&1))
                    color[i][j]=1;
        }
    }
}
void solve1()
{
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(color[i][j])
                s1+=w[i][j];
            else
                s2+=w[i][j];
    d=abs(s1-s2);
    if(Graph.check(d))
        printf("%lld\n",ans);
    else
        puts("-1");
}
void solve2()
{
    int l=0,r=10000000000000000;
    if(!Graph.check(r))
    {
        puts("-1");
        return;
    }
    while(l+1!=r)
    {
        int mid=(l+r)>>1;
        if(Graph.check(mid))
            r=mid;
        else
            l=mid;
    }
    Graph.check(r);
    printf("%lld\n",ans);
}
void init()
{
    Graph.init();
    ans=s1=s2=tot=0;
    scanf("%lld %lld",&n,&m);
    memset(color,0,sizeof(color));
    memset(w,0,sizeof(w));
    colored();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf("%lld",&w[i][j]);
            id[i][j]=++tot;
            _w[tot]=w[i][j];
        }
    Graph.S=++tot,Graph.T=++tot;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(color[i][j])
            {
                Graph.add(Graph.S,id[i][j],0);
                if(w[i-1][j])
                    Graph.add(id[i][j],id[i-1][j],LONG_LONG_MAX);
                if(w[i+1][j])
                    Graph.add(id[i][j],id[i+1][j],LONG_LONG_MAX);
                if(w[i][j+1])
                    Graph.add(id[i][j],id[i][j+1],LONG_LONG_MAX);
                if(w[i][j-1])
                    Graph.add(id[i][j],id[i][j-1],LONG_LONG_MAX);
            }
            else
                Graph.add(id[i][j],Graph.T,0);
    if((n*m)&1)
        solve1();
    else
        solve2();
}
main()
{
#ifndef ONLINE_JUDGE
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
#endif
    scanf("%lld",&T);
    while(T--)
    {
        init();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章