1. 程式人生 > >BZOJ 3171 TJOI2013迴圈格

BZOJ 3171 TJOI2013迴圈格

Problem

BZOJ

Solution

很有意思的一道題目

先講講怎麼建圖:
把每個格子拆成入點 u x u_x 和出點 v x

v_x ,對於每個格子的入點依次向四周格子的出點連邊,方向和給定方向一樣則費用為0,否則費用為1。源點向入點連流量為1,費用為0的邊,出點向匯點連流量為1,費用為0的邊。

那麼我們就想要證明每個最大匹配都對應一個完美格子。
其實證明並不難,對於最大匹配下,如果 u x

u_x 的流量流向了 v y v_y ,我們就在位置 x x
上寫下 y y ,那麼顯然我們會得到一個排列。我們可以把這個看做群論上的一種置換,那麼它就可以被拆成一個或多個迴圈,所以每個格子都可以走回到自己的位置。

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;
}