[bzoj3171]循环格
如果把这个矩阵看成一张图,题目相当于要求每一个点的入度和出度都是1(也就是有很多环),否则指向环的点就无法走回自己了
将所有点拆成两个,S向原来的点流(1,0)的边,拆出来的点向T连(1,0)的边,然后每一个点指向初始方向上的点(1,0)的边,指向非初始方向上(1,1)的边,求最小费用最大流即可(也就是让其满足此条件)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1005 4 struct ji{ 5 int nex,to,len,cost; 6 }edge[N<<2]; 7 queue<int>q; 8 int E,n,m,x,y,ans,dx[4]={-1,0,0,1},dy[4]={0,-1,1,0},head[N],vis[N],d[N],from[N]; 9 char c[4]={'U','L','R','D'},s[N]; 10 int id(int x,int y){ 11 return x*m+y+1; 12 } 13 void add(int x,int y,int z,int w){ 14 edge[E].nex=head[x]; 15 edge[E].to=y; 16 edge[E].len=z; 17 edge[E].cost=w; 18 head[x]=E++; 19 if (E&1)add(y,x,0,-w); 20 } 21 bool spfa(){ 22 memset(d,0x3f,sizeof(d)); 23 memset(vis,0,sizeof(vis)); 24 q.push(0); 25 d[0]=0; 26 while (!q.empty()){ 27 int k=q.front(); 28 q.pop(); 29 for(int i=head[k];i!=-1;i=edge[i].nex){ 30 int v=edge[i].to; 31 if ((edge[i].len)&&(d[v]>d[k]+edge[i].cost)){ 32 from[v]=i; 33 d[v]=d[k]+edge[i].cost; 34 if (!vis[v]){ 35 vis[v]=1; 36 q.push(v); 37 } 38 } 39 } 40 vis[k]=0; 41 } 42 return d[2*n*m+1]<0x3f3f3f3f; 43 } 44 int main(){ 45 scanf("%d%d",&n,&m); 46 memset(head,-1,sizeof(head)); 47 for(int i=0;i<n;i++) 48 for(int j=0;j<m;j++){ 49 add(0,id(i,j),1,0); 50 add(id(i,j)+n*m,2*n*m+1,1,0); 51 } 52 for(int i=0;i<n;i++){ 53 scanf("%s",s); 54 for(int j=0;j<m;j++) 55 for(int k=0;k<4;k++){ 56 x=(i+dx[k]+n)%n; 57 y=(j+dy[k]+m)%m; 58 add(id(i,j),id(x,y)+n*m,1,(c[k]!=s[j])); 59 } 60 } 61 while (spfa()){ 62 ans+=d[2*n*m+1]; 63 for(int i=2*n*m+1;i;i=edge[from[i]^1].to){ 64 edge[from[i]].len--; 65 edge[from[i]^1].len++; 66 } 67 } 68 printf("%d",ans); 69 }