【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\n",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 }
3171: [Tjoi2013]循环格
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 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
RRRD
URLL
LRRR
Sample Output
2
HINT
1<=R,L<=15