BZOJ 3171 TJOI2013迴圈格
阿新 • • 發佈:2019-01-04
Problem
Solution
很有意思的一道題目
先講講怎麼建圖:
把每個格子拆成入點
和出點
,對於每個格子的入點依次向四周格子的出點連邊,方向和給定方向一樣則費用為0,否則費用為1。源點向入點連流量為1,費用為0的邊,出點向匯點連流量為1,費用為0的邊。
那麼我們就想要證明每個最大匹配都對應一個完美格子。
其實證明並不難,對於最大匹配下,如果
的流量流向了
,我們就在位置
上寫下
,那麼顯然我們會得到一個排列。我們可以把這個看做群論上的一種置換,那麼它就可以被拆成一個或多個迴圈,所以每個格子都可以走回到自己的位置。
Code
#include <assert.h>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int v[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
x=0;int f=0;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
if(f) x=-x;
}
int n,m,tot,id[20][20];
char s[20][20];
struct data{int v,w,c,nxt;};
struct Mcmf{
const static int N=510,M=3010;
int p,S,T,dfc,head[N],dis[N],inq[N],vis[N];
data edge[M];
queue<int> q;
Mcmf(){p=1;S=N-2;T=N-1;}
void insert(int u,int v,int w,int c)
{
edge[++p]=(data){v,w,c,head[u]};head[u]=p;
edge[++p]=(data){u,0,-c,head[v]};head[v]=p;
}
int bfs(int s,int t)
{
while(!q.empty()) inq[q.front()]=0,q.pop();
memset(dis,0x3f,sizeof(dis));
int x;dis[t]=0;inq[t]=1;q.push(t);
while(!q.empty())
{
x=q.front();q.pop();inq[x]=0;
for(int i=head[x];i;i=edge[i].nxt)
if(edge[i^1].w&&getmin(dis[edge[i].v],dis[x]-edge[i].c))
{
if(!inq[edge[i].v]) q.push(edge[i].v),inq[edge[i].v]=1;
}
}
return dis[s]<INF;
}
int dfs(int x,int t,int flow)
{
vis[x]=dfc;
if(x==t||!flow) return flow;
int rest=0,tmp;
for(int i=head[x];i;i=edge[i].nxt)
if(vis[edge[i].v]^dfc&&edge[i].w&&dis[edge[i].v]==dis[x]-edge[i].c)
{
tmp=dfs(edge[i].v,t,min(edge[i].w,flow-rest));
rest+=tmp;edge[i].w-=tmp;edge[i^1].w+=tmp;
if(rest==flow) break;
}
return rest;
}
int work()
{
int fw=0,fe=0,tmp;
while(bfs(S,T))
{
for(vis[T]=++dfc;vis[T]==dfc;)
{
++dfc;tmp=dfs(S,T,INF);
fw+=tmp;fe+=tmp*dis[S];
}
}
return fe;
}
}G;
void adj(int &x,int lim){if(x==0) x=lim;if(x>lim) x=1;}
int ch(char x)
{
if(x=='U') return 0;
if(x=='R') return 1;
if(x=='D') return 2;
if(x=='L') return 3;
assert(0);
}
void input()
{
int dir,xx,yy;
read(n);read(m);tot=n*m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
id[i][j]=(i-1)*m+j;
G.insert(G.S,id[i][j],1,0);
G.insert(id[i][j]+tot,G.T,1,0);
}
for(int i=1;i<=n;i++)
{
scanf("%s",s[i]+1);
for(int j=1;j<=m;j++)
{
dir=ch(s[i][j]);
for(int r=0;r<4;r++)
{
xx=i+v[r][0];yy=j+v[r][1];adj(xx,n);adj(yy,m);
G.insert(id[i][j],id[xx][yy]+tot,1,(dir!=r));
}
}
}
}
int main()
{
input();
printf("%d\n",G.work());
return 0;
}