BZOJ3171: [Tjoi2013]循环格
网络流·费用流
题解:
我们发现在最后的完美状态中,一个格子的入度=出度=1.
可以看出,只要满足所有格子入度=出度=1,就一定是一个完美循环。
把每个格子拆点,S向每个左边的点连容量1费用0的边
每个右边点向T连容量1,费用0的边
每个格子向四周连容量为1,如果原来指向的就是这个方向则费用为0,否则费用为1。
这样,与S连的边容量为1,保证了出度=1;与T连的边容量为1,保证了入度=1。走中间的一条边代表一个箭头带来的匹配,视情况有0或1的费用。
Code:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#define D(x) cout<<#x<<" = "<<x<<" "
#define E cout<<endl
using namespace std;
const int N = 15*15*2+5;
const int INF = 0x3f3f3f3f;
const int dx[4] = {-1,0,1,0};
const int dy[4] = {0,1,0,-1};
int n,m,S,T,ptr[16][16];
map<char,int> dic;
char str[16];
struct Edge{
int from,to,next,cap,flow,cost;
} e[1000005];
int head[N], ec=1;
void add(int a,int b,int cap,int cost){
ec++; e[ec].cap=cap; e[ec].flow=0; e[ec].cost=cost;
e[ec].from=a; e[ec].to=b; e[ec].next=head[a]; head[a]=ec;
}
void add2(int a,int b,int cap,int cost){
// D(a); D(b); D(cap); D(cost); E;
add(a,b,cap,cost); add(b,a,0,-cost);
}
int dis[N],pre[N]; bool vis[N];
bool spfa(){
memset(dis,0x3f,sizeof(dis));
memset(vis,false,sizeof(vis));
queue<int> q; q.push(S); vis[S]=true; dis[S]=0;
while(!q.empty()){
int u=q.front(); q.pop(); vis[u]=false;
for(int i=head[u];i;i=e[i].next){
if(e[i].cap == e[i].flow) continue;
int v=e[i].to;
if(dis[v] > dis[u]+e[i].cost){
dis[v]=dis[u]+e[i].cost; pre[v]=i;
if(!vis[v]){ vis[v]=true; q.push(v); }
}
}
}
return dis[T]!=INF;
}
int mxf(){
int ans=0;
while(spfa()){
int a=INF;
for(int i=pre[T];i;i=pre[e[i].from]) a=min(a, e[i].cap-e[i].flow);
for(int i=pre[T];i;i=pre[e[i].from]){
ans+=e[i].cost*a; e[i].flow+=a; e[i^1].flow-=a;
}
// D(a); D(ans); E;
}
return ans;
}
inline int id(int x,int y,int op){ return (m*(x-1)+y)*2-1+op; }
//inline bool check(int x,int y){ return x>=1 && x<=n && y>=1 && y<=m; }
void build(){
ec=1; memset(head,0,sizeof(head));
S=n*m*2+1; T=S+1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
add2(S,id(i,j,0),1,0);
add2(id(i,j,1),T,1,0);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int k=0;k<4;k++){
int ii=i+dx[k], jj=j+dy[k];
if(ii<1) ii=n; if(ii>n) ii=1;
if(jj<1) jj=m; if(jj>m) jj=1;
if(ptr[i][j]==k) add2(id(i,j,0),id(ii,jj,1),1,0);
else add2(id(i,j,0),id(ii,jj,1),1,1);
}
}
}
}
int main(){
dic['U']=0; dic['R']=1; dic['D']=2; dic['L']=3;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",str);
for(int j=1;j<=m;j++){
ptr[i][j]=dic[str[j-1]];
}
}
build(); int ans=mxf();
printf("%d\n",ans);
}