题目链接: http://codeforces.com/gym/257279/problem/C
题意:
你有一个 n ∗ m n*m n∗m 的矩阵,这些方格中有数字 1 − n ∗ m / 2 1-n*m/2 1−n∗m/2 每个数字出现两次,现在要你选出最少的方格个数,使得在这些方格内数字可以任意交换的情况下,可以实现两个相同的数字邻接。
做法:
感觉就是用图论做,就是网络流建不出图来…和队友综合一下应该就能过了…
大概就是,假设我们已经知道了最后的排列分布,它一定是某个含横竖长度为 2 2 2 的线段图,在这个图中,如果和原来的排列不同的会产生贡献。
因为 n ∗ m n*m n∗m 一定为偶数,我们从原点向所有的 i + j i+j i+j 奇数连边,偶数向汇点连边,每个奇数点只向四周的偶数点连边,就可以保证可以得到像上面那样结果的构图。
代码
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=7000;
const int maxm=100005;
const int inf=0x3f3f3f3f;
int dis[maxn],mp[85][85];
int vis[maxn],pre[maxn];
int head[maxn],cnt;
int n,m,sp,tp;
ll ans=0;
struct node{
int to,cap,cost,next;
}e[maxm];
void add(int from,int to,int cap,int cost){
e[cnt].to=to; e[cnt].cap=cap;
e[cnt].cost=cost; e[cnt].next=head[from];
head[from]=cnt++;
e[cnt].to=from; e[cnt].cap=0;
e[cnt].cost=-cost; e[cnt].next=head[to];
head[to]=cnt++;
}
bool spfa(int s,int t,int &flow,int &cost){
queue<int> q;
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
dis[s]=0; q.push(s);
vis[s]=1;
int d=inf;
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(e[i].cap>0&&dis[v]>dis[u]+e[i].cost){
dis[v]=dis[u]+e[i].cost;
pre[v]=i;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
if(dis[t]==inf){
return false;
}
for(int i=pre[t];~i;i=pre[e[i^1].to]){
d=min(d,e[i].cap);
}
for(int i=pre[t];~i;i=pre[e[i^1].to]){
e[i].cap-=d;
e[i^1].cap+=d;
cost+=e[i].cost*d;
}
flow+=d;
return true;
}
int mcmf(int s,int t){
int flow=0,cost=0;
while(spfa(s,t,flow,cost)){
//cout<<flow<<" "<<cost<<endl;
}
return cost;
}
int G(int x,int y){
return (x-1)*m+y;
}
int Same(int xl,int yl,int xr,int yr){
return mp[xl][yl]!=mp[xr][yr];
}
int main(){
memset(head,-1,sizeof(head));
ans=0;
scanf("%d%d",&n,&m);
sp=0;tp=m*n+1;
rep(i,1,n) rep(j,1,m) scanf("%d",&mp[i][j]);
rep(i,1,n){
rep(j,1,m){
if((i+j)&1){
add(sp,G(i,j),1,0);
if(i>1) add(G(i,j),G(i-1,j),1,Same(i,j,i-1,j));
if(j>1) add(G(i,j),G(i,j-1),1,Same(i,j,i,j-1));
if(j<m) add(G(i,j),G(i,j+1),1,Same(i,j,i,j+1));
if(i<n) add(G(i,j),G(i+1,j),1,Same(i,j,i+1,j));
}
else add(G(i,j),tp,1,0);
}
}
cout<<mcmf(sp,tp)<<endl;
return 0;
}