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

时间: 2024-08-07 14:05:11

【BZOJ】【3171】【TJOI2013】循环格的相关文章

BZOJ 3171: [Tjoi2013]循环格( 费用流 )

每个点都在某个环中, 出度都为1, 只要让入度也全为1就可以满足题意了. 然后就是裸的最小费用最大流了. ---------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<deque> #include<bitset> using n

bzoj 3171: [Tjoi2013]循环格

1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define M 10000 5 #define inf 2139062143 6 using namespace std; 7 int cnt=1,n,m,ans,T,d[M],q[2*M],f[M],head[M],next[10*M],u[10*M],v[10*M],w[10*M],fro[10*M],fr[M]; 8 int mp[100

bzoj 3171 [Tjoi2013]循环格(MCMF)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3171 [题意] 给定一个方向矩阵,要求改变最少的格子,使得任意一个点都在一个环中. [思路] 任意一个点位于一个环中,即等价于所有的点都有且仅有一个后继. 对于一个点构建X Y结点. 连边(S,Xi,1,0),(Yi,T,1,0).对于原来可以转移到的点连边(Xi,Yj,1,0),对于需要变换才能转移到的连边(Xi,Yk,1,1). 求最小费用最大流.最大流保证了每一个点都会有一个后

BZOJ3171: [Tjoi2013]循环格

题解: 从一个点出发回到这个点? 那我们就把每个点拆成两个点i,i’ 开始连边 s 到 i’,i 到 t. 相邻的连边 j‘ 到 i,费用等于方向改变的话就是1,否则为0. 然后跑费用流就可以了. 代码: 1 #include<cstdio> 2 3 #include<cstdlib> 4 5 #include<cmath> 6 7 #include<cstring> 8 9 #include<algorithm> 10 11 #include&

【BZOJ 3171】 [Tjoi2013]循环格

Description 一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子.每个元素有一个坐标(行,列),其中左上角元素坐标为(0,0).给定一个起始位置(r,c) ,你可以沿着箭头防线在格子间行走.即如果(r,c)是一个左箭头,那么走到(r,c-1);如果是右箭头那么走到(r,c+1):如果是上箭头那么走到(r-1,c):如果是下箭头那么走到(r+1,c):每一行和每一列都是循环的,即如果走出边界,你会出现在另一侧.一个完美的循环格是这样定义的:对于任意一个起始位置,你都可以i沿着箭

[TJOI2013]循环格

题目链接 戳我 \(Solution\) 我们观察发现循环格要满足每个点的入度都为\(1\) 证明: 我们假设每个点的入读不一定为\(1\),那么必定有一个或多个点的入度为0,那么则不满足循环格的定义,所以假设错误.所以每个点的入度必然为1. 所以这样我们就可以开始建图了.先进行拆点操作,将每个点拆成\(x\)和\(x'\)将\(x\)和\(S\)连接,流量为\(1\),费用为\(0\)再将\(x'\)和\(T\)连接,流量为\(1\),费用为\(0\) 最后对于每个点\(x\)将它和四周的\(

bzoj 3171(费用流)

3171: [Tjoi2013]循环格 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 785  Solved: 493 [Submit][Status][Discuss] Description 一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子.每个元素有一个坐标(行,列),其中左上角元素坐标为(0,0).给定一个起始位置(r,c) ,你可以沿着箭头防线在格子间行走.即如果(r,c)是一个左箭头,那么走到(r,c-1);如果是右箭头那

BZOJ 3171 循环格(费用流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3171 题意: 思路:若能构成循环,则每个格子的入度出度 均为1.因此将每个点拆成两个点x1,x2,分别作为出点和入点.出点向周围四个点的入点连边,流1,费用视该格子的字母而定.该格子的字母正好是这个方 向则费用为0否则为1.原点S向每个出点连边,流量1费用0:每个入点向汇点连边,流量1费用0.求最小费用最大流即可. struct node { int u,v,next,cost,cap

BZOJ 3172: [Tjoi2013]单词 &&  BZOJ 2434 [Noi2011]阿狸的打字机 (施工中)

fail树 链接地址 定义 把所有fail指针逆向,这样就得到了一棵树 (因为每个节点的出度都为1,所以逆向后每个节点入度为1,所以得到的是一棵树) 还账… 有了这个东西,我们可以做很多事… 对于AC自动机的构造前面的文章已经讲了,而在查询的时候,有一点感觉没有说清楚: 对于x串在y串中出现,必然是在y串某个前缀的后缀与x串相同 fail指针指向与该节点表示串后缀相等的且长度最大的串(或前缀)的节点 然后,根据fail指针的原理,在查询的时候,沿着当前节点的fail指针向上查找,直到root结束