[TJOI2013]循环格

费用流,

因为要求全部都是回路, 每个点出入度都为1,拆点分别代表出点和入点,剩下不多说。

注意边界可以走 即n->1

/**

 * Problem:Grid

 * Author:Shun Yao

 * Time:2013.5.21

 * Result:Accepted

 * Memo:CostFlow

 */



#include <cstring>

#include <cstdlib>

#include <cstdio>



using namespace std;



const long dir[2][4] = {{0, 0, -1, 1}, {-1, 1, 0, 0}}, Maxt = 452;



long s, t, ans, p2[Maxt], q[Maxt], *l, *r;

long d[Maxt];

char inq[Maxt];



class gnode {

public:

	long v, w;

	char f;

	gnode *op, *next;

	gnode() {}

	~gnode() {}

	gnode(long V, long W, char F, gnode *o, gnode *ne):v(V), w(W), f(F), op(o), next(ne) {}

} *g[Maxt], *p1[Maxt];



void add(long x, long y, long w) {

	g[x] = new gnode(y, w, 1, 0, g[x]);

	g[y] = new gnode(x, -w, 0, g[x], g[y]);

	g[x]->op = g[y];

}



char spfa() {

	static long i;

	static gnode *e;

	memset(d, 0x7f, sizeof d);

	d[s] = 0;

	memset(inq, 0, sizeof inq);

	inq[s] = 1;

	l = q;

	*l = s;

	r = l + 1;

	while (l != r) {

		inq[*l] = 0;

		if (d[*l] == 0x7f7f7f7f) {

			++l;

			if (l == q + Maxt)

				l = q;

			continue;

		}

		for (e = g[*l]; e; e = e->next)

			if (e->f && d[e->v] > d[*l] + e->w) {

				d[e->v] = d[*l] + e->w;

				p1[e->v] = e;

				p2[e->v] = *l;

				if (!inq[e->v]) {

					inq[e->v] = 1;

					*r = e->v;

					++r;

					if (r == q + Maxt)

						r = q;

				}

			}

		++l;

		if (l == q + Maxt)

			l = q;

	}

	if (d[t] == 0x7f7f7f7f)

		return 0;

	ans += d[t];

	for (i = t; i != s; i = p2[i]) {

		p1[i]->f = !p1[i]->f;

		p1[i]->op->f = !p1[i]->op->f;

	}

	return 1;

}



int main() {

	static long n, m, i, j, k, x, y, z;

	static char ch;

	freopen("grid.in", "r", stdin);

	freopen("grid.out", "w", stdout);

	scanf("%ld%ld", &n, &m);

	s = (n * m) << 1;

	t = s + 1;

	for (i = 0; i < n; ++i) {

		for (j = 0; j < m; ++j) {

			add(s, i * m + j, 0);

			add(i * m + j + n * m, t, 0);

			scanf(" %c", &ch);

			switch (ch) {

			case 'L':z = 0;break;

			case 'R':z = 1;break;

			case 'U':z = 2;break;

			case 'D':z = 3;break;

			}

			for (k = 0; k < 4; ++k) {

				x = (i + dir[0][k] + n) % n;

				y = (j + dir[1][k] + m) % m;

				add(i * m + j, x * m + y + n * m, k != z);

			}

		}

	}

	ans = 0;

	while (spfa());

	printf("%ld", ans);

	fclose(stdin);

	fclose(stdout);

	return 0;

}

 

你可能感兴趣的:(循环)