bzoj2668 [cqoi2012]交换棋子

来源:互联网 发布:翅片式换热器计算软件 编辑:程序博客网 时间:2024/05/17 23:36

【题意】

n*m棋盘,每次可以交换相邻(八连通)棋子,每个格子交换次数存在上限,求将初始棋盘置换为目标棋盘的最少交换次数。

【数据范围】

n<=20,m<=20,0<=交换次数<=9

【思路】

费用流

将每次交换看成白棋子的移动,则流量为白棋子总数,答案即最小费用,求最小费用最大流

关键在于交换次数上限问题,对于每个点,将上限适当修改后,限制的是这个点的流入量+流出量的和,因为流入量=流出量,故修改后的上限除以二即可得到该点流量限制

注意这题是八连通。。

【时间复杂度】

费用流,点数O(n^2),边数O(n^2)

#include<cstdio>#include<cstring>#include<algorithm>#define N 810#define inf 2147483647using namespace std; const int dx[8]={-1, -1, -1, 0, 0, 1, 1, 1};const int dy[8]={-1, 0, 1, -1, 1, -1, 0, 1};struct edge{int x, y, l, c, next;}a[100010];int n, m, m1[30][30], m2[30][30], m3[30][30], ans, cost, p[N], flag[N], h[N], S, T, fa[N],l, op, cl, d[N], x, sum1, sum2, xx, yy;char s[30]; void add(int x, int y, int ll, int c){    a[++l].x=x; a[l].y=y; a[l].l=ll; a[l].c=c; a[l].next=p[x]; p[x]=l;    a[++l].x=y; a[l].y=x; a[l].l=0; a[l].c=-c; a[l].next=p[y]; p[y]=l;} int spfa(){    memset(flag, 0, sizeof(flag));    for(int i=0; i<=T; i++){h[i]=inf; fa[i]=0;} h[S]=0; flag[S]=1;    op=0; cl=1; d[1]=S;    while(op!=cl){        op++; if(op>809)op=1; int v=d[op];        for(int i=p[v]; i; i=a[i].next)            if(a[i].l&&h[a[i].y]>h[v]+a[i].c){                h[a[i].y]=h[v]+a[i].c;                fa[a[i].y]=i;                if(!flag[a[i].y]){                    flag[a[i].y]=1;                    cl++; if(cl>809)cl=1; d[cl]=a[i].y;                }            }        flag[v]=0;    }    return fa[T]?1:0;}void dfs(){    int mn=inf;    for(int i=fa[T]; i; i=fa[a[i].x])mn=min(mn, a[i].l); ans+=mn;    for(int i=fa[T]; i; i=fa[a[i].x]){        cost+=mn*a[i].c; a[i].l-=mn; a[i^1].l+=mn;    }} int main(){    scanf("%d%d", &n, &m);    for(int i=1; i<=n; i++){        scanf("%s", s+1);        for(int j=1; j<=m; j++)m1[i][j]=s[j]-'0';    }    for(int i=1; i<=n; i++){        scanf("%s", s+1);        for(int j=1; j<=m; j++)m2[i][j]=s[j]-'0';    }    for(int i=1; i<=n; i++){        scanf("%s", s+1);        for(int j=1; j<=m; j++)m3[i][j]=s[j]-'0';    }    l=1; memset(p, 0, sizeof(p)); S=0; T=n*m*2+1;    for(int i=1; i<=n; i++)        for(int j=1; j<=m; j++){            x=(i-1)*m+j;            if(m1[i][j])add(S, x, 1, 0);            if(m2[i][j])add(n*m+x, T, 1, 0);            add(x, n*m+x, (m3[i][j]+m1[i][j]+m2[i][j])/2, 0);            for(int k=0; k<=7; k++){                xx=i+dx[k]; yy=j+dy[k];                if(1<=xx&&xx<=n&&1<=yy&&yy<=m)add(n*m+x, (xx-1)*m+yy, inf, 1);            }        }       sum1=sum2=0;    for(int i=1; i<=n; i++)        for(int j=1; j<=m; j++){sum1+=m1[i][j]; sum2+=m2[i][j];}    if(sum1!=sum2){printf("-1"); return 0;}    ans=cost=0;    while(spfa())dfs();    if(ans!=sum1){printf("-1"); return 0;}    printf("%d", cost);    return 0;}


0 0
原创粉丝点击