【BZOJ】【3171】【TJOI2013】循环格

网络流/费用流


  最后能走回出发点……说明全部是环= =

  而二分图上的环说明什么呢……完备匹配

  对于每个点,它都有四个可能的匹配点,且已知它已经(伪)匹配的一个点,那么我们于已知每条(伪)匹配边,我们连(i,j)->(x,y)' 流量为1,费用为0,表示不用修改,然后对(x,y)'我们向另外三个可能的匹配点连边,流量为1,费用为1,表示修改这个点的匹配对象的代价。

  然后对于每个点连S->(i,j) 流量为1,费用为0,(i,j)'->T,流量为1,费用为0。保证每个点有且仅有一个匹配点

  1 /**************************************************************
  2     Problem: 3171
  3     User: Tunix
  4     Language: C++
  5     Result: Accepted
  6     Time:28 ms
  7     Memory:5968 kb
  8 ****************************************************************/
  9  
 10 //BZOJ 3171
 11 #include<cmath>
 12 #include<vector>
 13 #include<cstdio>
 14 #include<cstring>
 15 #include<cstdlib>
 16 #include<iostream>
 17 #include<algorithm>
 18 #define rep(i,n) for(int i=0;i<n;++i)
 19 #define F(i,j,n) for(int i=j;i<=n;++i)
 20 #define D(i,j,n) for(int i=j;i>=n;--i)
 21 #define pb push_back
 22 #define CC(a,b) memset(a,b,sizeof(a))
 23 using namespace std;
 24 int getint(){
 25     int v=0,sign=1; char ch=getchar();
 26     while(!isdigit(ch)) {if(ch=='-') sign=-1; ch=getchar();}
 27     while(isdigit(ch))  {v=v*10+ch-'0'; ch=getchar();}
 28     return v*sign;
 29 }
 30 const int N=500,M=200000,INF=~0u>>2;
 31 const double eps=1e-8;
 32 /*******************template********************/
 33 int n,m,ans,flow,tot;
 34 inline int pack(int i,int j){
 35     if (i==0) i=n;
 36     if (i==n+1) i=1;
 37     if (j==0) j=m;
 38     if (j==m+1) j=1;
 39     return (i-1)*m+j;
 40 }
 41 struct edge{int from,to,v,c;};
 42 struct Net{
 43     edge E[M];
 44     int head[N],next[M],cnt;
 45     void ins(int x,int y,int z,int c){
 46         E[++cnt]=(edge){x,y,z,c};
 47         next[cnt]=head[x]; head[x]=cnt;
 48     }
 49     void add(int x,int y,int z,int c){
 50         ins(x,y,z,c); ins(y,x,0,-c);
 51     }
 52     int from[N],Q[M],d[N],S,T;
 53     bool inq[N];
 54     bool spfa(){
 55         int l=0,r=-1;
 56         F(i,0,T) d[i]=INF;
 57         Q[++r]=S; d[S]=0; inq[S]=1;
 58         while(l<=r){
 59             int x=Q[l++]; inq[x]=0;
 60             for(int i=head[x];i;i=next[i])
 61                 if(E[i].v && d[x]+E[i].c<d[E[i].to]){
 62                     d[E[i].to]=d[x]+E[i].c;
 63                     from[E[i].to]=i;
 64                     if(!inq[E[i].to]){
 65                         Q[++r]=E[i].to;
 66                         inq[E[i].to]=1;
 67                     }
 68                 }
 69         }
 70         return d[T]!=INF;
 71     }
 72     void mcf(){
 73         int x=INF;
 74         for(int i=from[T];i;i=from[E[i].from])
 75             x=min(x,E[i].v);
 76         for(int i=from[T];i;i=from[E[i].from]){
 77             E[i].v-=x;
 78             E[i^1].v+=x;
 79         }
 80         ans+=x*d[T];
 81     }
 82     void init(){
 83         n=getint(); m=getint(); cnt=1;
 84         S=0; T=2*n*m+1; tot=n*m;
 85         char s[100];
 86         F(i,1,n){
 87             scanf("%s",s);
 88             F(j,1,m){
 89                 add(S,pack(i,j),1,0);
 90                 if (s[j-1]=='U'){
 91                     add(pack(i,j),tot+pack(i-1,j),1,0);
 92                     add(tot+pack(i-1,j),tot+pack(i+1,j),1,1);
 93                     add(tot+pack(i-1,j),tot+pack(i,j-1),1,1);
 94                     add(tot+pack(i-1,j),tot+pack(i,j+1),1,1);
 95                 }
 96                 if (s[j-1]=='L'){
 97                     add(pack(i,j),tot+pack(i,j-1),1,0);
 98                     add(tot+pack(i,j-1),tot+pack(i,j+1),1,1);
 99                     add(tot+pack(i,j-1),tot+pack(i-1,j),1,1);
100                     add(tot+pack(i,j-1),tot+pack(i+1,j),1,1);
101                 }
102                 if (s[j-1]=='D'){
103                     add(pack(i,j),tot+pack(i+1,j),1,0);
104                     add(tot+pack(i+1,j),tot+pack(i-1,j),1,1);
105                     add(tot+pack(i+1,j),tot+pack(i,j+1),1,1);
106                     add(tot+pack(i+1,j),tot+pack(i,j-1),1,1);
107                 }
108                 if (s[j-1]=='R'){
109                     add(pack(i,j),tot+pack(i,j+1),1,0);
110                     add(tot+pack(i,j+1),tot+pack(i,j-1),1,1);
111                     add(tot+pack(i,j+1),tot+pack(i+1,j),1,1);
112                     add(tot+pack(i,j+1),tot+pack(i-1,j),1,1);
113                 }
114                 add(tot+pack(i,j),T,1,0);
115             }
116         }
117         while(spfa()) mcf();
118         printf("%d
",ans);
119     }
120 }G1;
121 int main(){
122 #ifndef ONLINE_JUDGE
123     freopen("input.txt","r",stdin);
124 //  freopen("output.txt","w",stdout);
125 #endif
126     G1.init();
127     return 0;
128 }
View Code

3171: [Tjoi2013]循环格

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 600  Solved: 359
[Submit][Status][Discuss]

Description

一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子。每个元素有一个坐标(行,列),其中左上角元素坐标为(0,0)。给定一个起始位置(r,c)

,你可以沿着箭头防线在格子间行走。即如果(r,c)是一个左箭头,那么走到(r,c-1);如果是右箭头那么走到(r,c+1);如果是上箭头那么走到 (r-1,c);如果是下箭头那么走到(r+1,c);每一行和每一列都是循环的,即如果走出边界,你会出现在另一侧。
一个完美的循环格是这样定义的:对于任意一个起始位置,你都可以i沿着箭头最终回到起始位置。如果一个循环格不满足完美,你可以随意修改任意一个元素的箭头直到完美。给定一个循环格,你需要计算最少需要修改多少个元素使其完美。

Input

第一行两个整数R,C。表示行和列,接下来R行,每行C个字符LRUD,表示左右上下。

Output

一个整数,表示最少需要修改多少个元素使得给定的循环格完美

Sample Input

3 4
RRRD
URLL
LRRR

Sample Output

2

HINT

1<=R,L<=15

Source

[Submit][Status][Discuss]
原文地址:https://www.cnblogs.com/Tunix/p/4354077.html