Codeforces 316C2 题解 (网络流-最小费用最大流)

来源:互联网 发布:unity3d 2d骨骼 编辑:程序博客网 时间:2024/05/16 07:49

题目描述

在一个n*m的网格图里面,每一个cell中有一个shoe,网格中共有n*m/2双鞋子,两个标号相同的鞋子被视为一双。我们视每一只鞋子都和与其配对的鞋子相邻(所在的格子有邻边)的状态为理想状态。题目给出当前状态,要求求出最少需要变化几只鞋子的位置才能达到理想状态。

Sample Input:

3 4
1 3 2 6
2 1 5 6
4 4 5 3

Sample Output:

4

Hint:

对于样例,只需要改变四只鞋子的位置(既图中灰色部分的鞋子)就可以达到理想状态。
样例说明


题解

这道题的模型并不明显,但是经过对题目性质的分析,我们就可以找到切入点。
贪心地想,为了在最短的步数之内达到理想状态,我们可知解题的两个性质:

  • 首先,对于某一只与可配对鞋子不相邻的鞋子,它或它的配对鞋一定是移动或被移动过的。
  • 对于每一对可匹配的鞋子,它们不会同时被移动。

那么我们可以考虑,将网格内的点分为两个集合,每个集合内的点都互不相邻。然后从源点向其中一个集合的点连一条流量为1权值为0的边,另一个集合的点向汇点连一条流量为1权值为0的边。对于与源点相连的那个集合的点,向相邻的点连边,可以匹配的连权值为0的边,不可匹配的连权值为1的边。
跑一边最小费用最大流可以得到答案。


代码

套路很深。

#include <cstdio>#include <iostream>#include <queue>#include <cstring>using namespace std;const int maxn=85;const int INF=int(1e9)+7;int n,m;int a[maxn][maxn];void read() {    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)            scanf("%d",&a[i][j]);    return;}const int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};const int maxd=maxn*maxn;const int maxe=int(1e5)+10;int tot=0;int head[maxd];int S,T;struct Edge {    int from,to,cap,cost,next;    Edge() {}    Edge(int x,int y,int a,int b,int c):from(x),to(y),cap(a),cost(b),next(c) {}}eage[maxe*2];void add(int x,int y,int a,int b) {    eage[tot]=Edge(x,y,a,b,head[x]), head[x]=tot++;    eage[tot]=Edge(y,x,0,-b,head[y]), head[y]=tot++;    return;}bool used[maxd],vis[maxd];int dis[maxd];queue<int> que;int ans=0;bool spfa() {    for(int i=0;i<maxd;i++) used[i]=false,dis[i]=INF,vis[i]=false;    while(que.size()) que.pop();    que.push(S);    used[S]=true;    dis[S]=0;    while(que.size()) {        int u=que.front(); que.pop();        used[u]=false;        for(int i=head[u];~i;i=eage[i].next) if(eage[i].cap && dis[eage[i].to]>dis[u]+eage[i].cost) {            int v=eage[i].to;            dis[v]=dis[u]+eage[i].cost;            if(!used[v]) {                used[v]=true;                que.push(v);            }        }    }    return (dis[T]<INF);}int dfs(int u,int flow) {    if(u==T) {        ans+=dis[u]*flow;        return flow;    }    vis[u]=true;    int ret=0;    for(int i=head[u];~i;i=eage[i].next) if(!vis[eage[i].to] && eage[i].cap && dis[eage[i].to]==dis[u]+eage[i].cost) {        int v=eage[i].to;        int newf=dfs(v,min(flow,eage[i].cap));        eage[i].cap-=newf;        eage[i^1].cap+=newf;        ret+=newf;        flow-=newf;        if(!flow) break;    }    if(!ret) dis[u]=-1;    return ret;}int MCMF() {    ans=0;    while(spfa()) dfs(S,INF);    return ans;}void build() {    tot=0;    memset(head,-1,sizeof head);    #define pos(i,j) (S+(i-1)*m+j)    S=1,T=pos(n,m)+1;    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++) {        if((i&1)==(j&1)) add(pos(i,j),T,1,0);        else {            add(S,pos(i,j),1,0);            for(int k=0;k<4;k++) {                int x=i+dir[k][0],y=j+dir[k][1];                if(x<1 || y<1 || x>n || y>m) continue;                add(pos(i,j),pos(x,y),1,(a[i][j]!=a[x][y]));            }        }    }    return;}int main() {    read();    build();    printf("%d\n",MCMF());    return 0;} 
1 0
原创粉丝点击