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][100],xx[4]={0,0,1,-1},yy[4]={-1,1,0,0};
  9 void jia1(int a1,int a2,int a3,int a4)
 10 {
 11     cnt++;
 12     next[cnt]=head[a1];
 13     head[a1]=cnt;
 14     fro[cnt]=a1;
 15     u[cnt]=a2;
 16     v[cnt]=a3;
 17     w[cnt]=a4;
 18 }
 19 void jia(int a1,int a2,int a3,int a4)
 20 {
 21     jia1(a1,a2,a3,a4);
 22     jia1(a2,a1,0,-a4);
 23     return;
 24 }
 25 bool spfa()
 26 {
 27     memset(d,127,sizeof(int)*(T+1));
 28     d[0]=0;
 29     f[0]=1;
 30     q[1]=0;
 31     int h=0,t=1;
 32     for(;h<t;)
 33       {
 34         h++;
 35         int p=q[h];
 36         f[p]=0;
 37           for(int i=head[p];i;i=next[i])
 38           if(v[i]&&d[u[i]]>d[p]+w[i])
 39             {
 40                 d[u[i]]=d[p]+w[i];
 41                 fr[u[i]]=i;
 42                 if(!f[u[i]])
 43                   {
 44                     f[u[i]]=1;
 45                     t++;
 46                     q[t]=u[i];
 47                     }
 48             }
 49       }
 50     if(d[T]!=inf)
 51       return 1;
 52     return 0;
 53 }
 54 void mcf()
 55 {
 56     int mx=inf;
 57     for(int i=fr[T];i;i=fr[fro[i]])
 58       mx=min(mx,v[i]);
 59     for(int i=fr[T];i;i=fr[fro[i]])
 60       {
 61         v[i]-=mx;
 62         v[i^1]+=mx;
 63         ans+=mx*w[i];
 64       }
 65     return;
 66 }
 67 int main()
 68 {
 69     char ch[20];
 70     scanf("%d%d",&n,&m);
 71     T=n*m*2+1;
 72     for(int i=1;i<=n;i++)
 73       {
 74         scanf("%s",ch+1);
 75         for(int j=1;j<=m;j++)
 76           {
 77             if(ch[j]==‘L‘)
 78               mp[i][j]=0;
 79             if(ch[j]==‘R‘)
 80               mp[i][j]=1;
 81             if(ch[j]==‘D‘)
 82               mp[i][j]=2;
 83             if(ch[j]==‘U‘)
 84               mp[i][j]=3;
 85           }
 86       }
 87     for(int i=1;i<=n;i++)
 88       for(int j=1;j<=m;j++)
 89         {
 90             jia(0,(i-1)*m+j,1,0);
 91             jia((i-1)*m+n*m+j,T,1,0);
 92             for(int k=0;k<4;k++)
 93               {
 94                 int nx=i+xx[k],ny=j+yy[k];
 95                 if(!nx)
 96                   nx=n;
 97                 if(!ny)
 98                   ny=m;
 99                 if(nx>n)
100                   nx=1;
101                 if(ny>m)
102                   ny=1;
103                 if(k==mp[i][j])
104                   jia((i-1)*m+j,(nx-1)*m+ny+n*m,1,0);
105                 else
106                   jia((i-1)*m+j,(nx-1)*m+ny+n*m,1,1);
107               }
108         }
109     for(;spfa();)
110       mcf();
111     printf("%d\n",ans);
112     return 0;
113 }

循环格出入度都等于1,与一开始方向不同的加上费用,跑费用流,

时间: 2024-10-24 07:54:58

bzoj 3171: [Tjoi2013]循环格的相关文章

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

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

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】【TJOI2013】循环格

网络流/费用流 最后能走回出发点……说明全部是环= = 而二分图上的环说明什么呢……完备匹配 对于每个点,它都有四个可能的匹配点,且已知它已经(伪)匹配的一个点,那么我们于已知每条(伪)匹配边,我们连(i,j)->(x,y)' 流量为1,费用为0,表示不用修改,然后对(x,y)'我们向另外三个可能的匹配点连边,流量为1,费用为1,表示修改这个点的匹配对象的代价. 然后对于每个点连S->(i,j) 流量为1,费用为0,(i,j)'->T,流量为1,费用为0.保证每个点有且仅有一个匹配点 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结束