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

每个点都在某个环中, 出度都为1, 只要让入度也全为1就可以满足题意了. 然后就是裸的最小费用最大流了.

----------------------------------------------------------------------------

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<deque>

#include<bitset>

using namespace std;

#define X(x, y) (((x) * C + y) << 1)

#define Y(x, y) (((x) * C + y) << 1 | 1)

const int maxn = 20;

const int maxv = maxn * maxn * 2;

const int INF = 0X3F3F3F3F;

const int dx[4] = {-1, 0, 0, 1};

const int dy[4] = {0, 1, -1, 0};

const char dc[4] = {‘U‘, ‘R‘, ‘L‘, ‘D‘};

int d[maxv], a[maxv];

int R, C, V, S, T;

char s[maxn];

bitset<maxv> inq;

deque<int> q;

struct edge {

int to, cap, cost;

edge *next, *rev;

} E[100000], *pt = E, *head[maxv], *p[maxv];

inline void Add(int u, int v, int c, int w) {

pt->to = v;

pt->cap = c;

pt->cost = w;

pt->next = head[u];

head[u] = pt++;

}

inline void AddEdge(int u, int v, int w) {

Add(u, v, 1, w);

Add(v, u, 0, -w);

head[u]->rev = head[v];

head[v]->rev = head[u];

}

void Solve() {

int ans = 0;

for( ; ; ) {

inq.reset();

memset(d, INF, sizeof(int) * V);

d[S] = 0;

a[S] = INF;

q.push_back(S);

while(!q.empty()) {

int x = q.front(); q.pop_front();

inq[x] = 0;

for(edge* e = head[x]; e; e = e->next) if(e->cap && d[e->to] > d[x] + e->cost) {

p[e->to] = e;

d[e->to] = d[x] + e->cost;

a[e->to] = min(a[x], e->cap);

if(inq[e->to] == 0) {

inq[e->to] = 1;

if(!q.empty() && d[q.front()] > d[e->to])

q.push_front(e->to);

else

q.push_back(e->to);

}

}

}

if(d[T] == INF)

break;

ans += d[T] * a[T];

for(int x = T; x != S; x = p[x]->rev->to) {

p[x]->cap -= a[T];

p[x]->rev->cap += a[T];

}

}

printf("%d\n", ans);

}

void Init() {

scanf("%d%d", &R, &C);

V = R * C * 2;

S = V++;

T = V++;

for(int i = 0; i < R; i++) {

scanf("%s", s);

for(int j = 0; j < C; j++) {

AddEdge(S, X(i, j), 0);

AddEdge(Y(i, j), T, 0);

for(int d = 0; d < 4; d++) {

int x = i + dx[d] + R, y = j + dy[d] + C;

while(x >= R) x -= R;

while(y >= C) y -= C;

AddEdge(X(i, j), Y(x, y), s[j] != dc[d]);

}

}

}

}

int main() {

Init();

Solve();

return 0;

}

----------------------------------------------------------------------------

3171: [Tjoi2013]循环格

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 672  Solved: 411
[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

时间: 2024-10-10 16:01:37

BZOJ 3171: [Tjoi2013]循环格( 费用流 )的相关文章

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). 求最小费用最大流.最大流保证了每一个点都会有一个后

BZOJ 3171 TJOI 2013 循环格 费用流

题目大意:给出一个表格,每个表格指向周围四个格子中的一个,问你可以改变一些格子上的指向,问让所有格子都在圈中最小需要改变多少. 思路:所有的格子都在圈中,由于每个格子只能有一个出边,所以就要保证所有格子都有一个入边.建立费用流的模型,所有点向汇点连流量1费用0的边,表示要接受一个入边.S向所有点连一条流量1费用0的边,表示一条出边.一个格子向周围四个格子连边,流量1,如果方向与当前方向相符,那么费用0,否则费用1.之后跑费用流就是答案了. CODE: #include <queue> #inc

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 2668 交换棋子(费用流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2668 题意:有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与m[i,j]次交换. 思路: 我们将1看做要移动的数字,将0看做空白.那么若1在始末状态个数不同则无解:如某个格子始末状态均有1则这个格子的1对结果无影响,可以将其都置为0.将每个格子拆为为个点p0,p1,p2: (1)若格子初始为1,则连边:<s,p0,1,0>

【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 1927: [Sdoi2010]星际竞速 费用流

1927: [Sdoi2010]星际竞速 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1927 Description 10 年一度的银河系赛车大赛又要开始了.作为全银河最盛大的活动之一, 夺得这个项目的冠军无疑是很多人的梦想,来自杰森座 α星的悠悠也是其中之一. 赛车大赛的赛场由 N 颗行星和M条双向星际航路构成,其中每颗行星都有 一个不同的引力值.大赛要

BZOJ 1449 JSOI2009 球队收益 费用流

题目大意:给定n支球队,第i支球队已经赢了wini场,输了losei场,接下来还有m场比赛,每个球队最终的收益为Ci?x2i+Di?y2i,其中xi为最终的胜场,yi为最终的负场 求最小化收益 考虑一只球队,其收益与在接下来的比赛中的胜场数关系为: 赢0场 Ci?win2i+Di?(di+losei)2 赢1场 Ci?(wini+1)2+Di?(di+losei?1)2 赢2场 Ci?(wini+2)2+Di?(di+losei?2)2 - 赢di场 Ci?(wini+di)2+Di?lose2