码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 2668 交换棋子(费用流)

时间:2014-06-23 00:42:45      阅读:223      评论:0      收藏:0      [点我收藏+]

标签:style   class   blog   http   tar   ext   

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2668

题意:有一个nm列的黑白棋盘,你每次可以交换两个相邻格子中的棋子,最终达到目标状态。要求第i行第j列的格子只能参与m[i,j]次交换。

思路: 我们将1看做要移动的数字,将0看做空白。那么若1在始末状态个数不同则无解;如某个格子始末状态均有1则这个格子的1对结果无影响,可以将其都置为0。将每个格子拆为为个点p0,p1,p2:

(1)若格子初始为1,则连边:<s,p0,1,0>,<p1,p0,m[i][j]/2,0)>,<p0,p2,(m[i][j]+1)/2,0>;

(2)若格子末状态为0,则连边:<p0,t,1,0>,<p1,p0,(m[i][j]+1)/2,0>,<p0,p2,m[i][j]/2,0>;

(3)始末都是空白,则连边:<p1,p0,m[i][j]/2,0>,<p0,p2,m[i][j]/2,0>;

(4)相邻格子x和y连边<px2,py1,INF,0>。

 

struct node
{
    int u,v,next,cost,cap;
};




node edges[N];
int head[N],e;




void add(int u,int v,int cap,int cost)
{
    edges[e].u=u;
    edges[e].v=v;
    edges[e].cap=cap;
    edges[e].cost=cost;
    edges[e].next=head[u];
    head[u]=e++;
}




void Add(int u,int v,int cap,int cost)
{
    add(u,v,cap,cost);
    add(v,u,0,-cost);
}








int pre[N],F[N],C[N],visit[N];




int SPFA(int s,int t,int n)
{
    int i;
    for(i=0;i<=n;i++) F[i]=0,C[i]=INF,visit[i]=0;
    queue<int> Q;
    Q.push(s); F[s]=INF; C[s]=0;
    int u,v,cost,cap;
    while(!Q.empty())
    {
        u=Q.front();
        Q.pop();
        
        visit[u]=0;
        for(i=head[u];i!=-1;i=edges[i].next)
        {
            if(edges[i].cap>0)
            {
                v=edges[i].v;
                cost=edges[i].cost;
                cap=edges[i].cap;
                if(C[v]>C[u]+cost)
                {
                    C[v]=C[u]+cost;
                    F[v]=min(F[u],cap);
                    pre[v]=i;
                    if(!visit[v]) visit[v]=1,Q.push(v);
                }
            }
        }
    }
    return F[t];
}


char a[25][25],b[25][25],c[25][25];
int d[25][25][3];
int dx[]={-1,-1,-1,0,1,1,1,0};
int dy[]={-1,0,1,1,1,0,-1,-1};
int n,m,s,t,cnt;
int ans;


int MCMF(int s,int t,int n)
{
    int i,x,temp,M=0;
    while(temp=SPFA(s,t,n))
    {
        M+=temp;
        for(i=t;i!=s;i=edges[pre[i]].u)
        {
            x=pre[i];
            ans+=edges[x].cost*temp;
            edges[x].cap-=temp;
            edges[x^1].cap+=temp;
        }
    }
    return M==cnt;
}






int main()
{
    RD(n,m);
    int i,j;
    FOR1(i,n) RD(a[i]+1);
    FOR1(i,n) RD(b[i]+1);
    FOR1(i,n) RD(c[i]+1);
    int k=0;
    FOR1(i,n) FOR1(j,m)
    {
        a[i][j]-=‘0‘;
        b[i][j]-=‘0‘;
        c[i][j]-=‘0‘;
        d[i][j][0]=++k;
        d[i][j][1]=++k;
        d[i][j][2]=++k;
        if(a[i][j]&&b[i][j]) a[i][j]=0,b[i][j]=0;
    }
    s=0; t=++k;
    clr(head,-1);
    cnt=0;
    int x,y,p=0;
    FOR1(i,n) FOR1(j,m)
    {
        if(a[i][j]) 
        {
            cnt++;
            Add(s,d[i][j][0],1,0);
            Add(d[i][j][1],d[i][j][0],c[i][j]/2,0);
            Add(d[i][j][0],d[i][j][2],(c[i][j]+1)/2,0);
        }
        else if(b[i][j])
        {
            p++;
            Add(d[i][j][0],t,1,0);
            Add(d[i][j][1],d[i][j][0],(c[i][j]+1)/2,0);
            Add(d[i][j][0],d[i][j][2],c[i][j]/2,0);
        }
        else 
        {
            Add(d[i][j][1],d[i][j][0],c[i][j]/2,0);
            Add(d[i][j][0],d[i][j][2],c[i][j]/2,0);
        }
        FOR0(k,8)
        {
            x=i+dx[k];
            y=j+dy[k];
            if(x>=1&&x<=n&&y>=1&&y<=m)
            {
                Add(d[i][j][2],d[x][y][1],INF,1);
            }
        }
    }
    if(cnt!=p||!MCMF(s,t,t+1)) puts("-1");
    else PR(ans);
}

 

 

 

BZOJ 2668 交换棋子(费用流),布布扣,bubuko.com

BZOJ 2668 交换棋子(费用流)

标签:style   class   blog   http   tar   ext   

原文地址:http://www.cnblogs.com/jianglangcaijin/p/3799793.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!