一名苦逼的OIer,想成为ACMer

Iowa_Battleship

洛谷1004 方格取数

原题链接
继续写水题中
\(DP\)水题。
不过费用流解更灵活,可以解决\(k\)条路。
所以就写了个费用流。

#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1e4 + 10;
int fi[N], ne[N], da[N], di[N], co[N], la[N], q[N], cn[N], dis[N], l = 1, st, ed, n;
bool v[N];
inline int re()
{
	int x = 0;
	char c = getchar();
	bool p = 0;
	for (; c < '0' || c > '9'; c = getchar())
		p |= c == '-';
	for (; c >= '0' && c <= '9'; c = getchar())
		x = x * 10 + c - '0';
	return p ? -x : x;
}
inline void add(int x, int y, int z, int c)
{
	di[++l] = y; da[l] = z; co[l] = c; ne[l] = fi[x]; fi[x] = l;
	di[++l] = x; da[l] = 0; co[l] = -c; ne[l] = fi[y]; fi[y] = l;
}
inline int minn(int x, int y) { return x < y ? x : y; }
inline int calc(int x, int y) { return (x - 1) * n + y; }
bool spfa()
{
	int i, x, y, head = 0, tail = 1;
	memset(dis, 250, sizeof(dis));
	dis[st] = 0;
	q[1] = st;
	while (head ^ tail)
	{
		x = q[++head];
		v[x] = 0;
		for (i = fi[x]; i; i = ne[i])
			if (dis[y = di[i]] < dis[x] + co[i] && da[i] > 0)
			{
				dis[y] = dis[x] + co[i];
				la[y] = x;
				cn[y] = i;
				if (!v[y])
				{
					q[++tail] = y;
					v[y] = 1;
				}
			}
	}
	return dis[ed] > -1e7;
}
int main()
{
	int i, j, x, y, z, o, k, s = 0;
	n = re();
	st = (o = n * n) << 1 | 1;
	ed = st + 1;
	while (1)
	{
		x = re(); y = re(); z = re();
		if (!x && !y && !z)
			break;
		k = calc(x, y);
		add(k, k + o, 1, z);
	}
	for (i = 1; i <= n; i++)
		for (j = 1; j <= n; j++)
		{
			x = calc(i, j);
			add(x, x + o, 1e9, 0);
			if (i < n)
				add(x + o, calc(i + 1, j), 1e9, 0);
			if (j < n)
				add(x + o, calc(i, j + 1), 1e9, 0);
		}
	add(st, 1, 2, 0);
	add(o << 1, ed, 2, 0);
	while (spfa())
	{
		int mi = 1e9;
		for (i = ed; i ^ st; i = la[i])
			mi = minn(mi, da[cn[i]]);
		s += mi * dis[ed];
		for (i = ed; i ^ st; i = la[i])
		{
			da[cn[i]] -= mi;
			da[cn[i] ^ 1] += mi;
		}
	}
	printf("%d", s);
	return 0;
}

posted on 2018-12-06 20:48  Iowa_Battleship  阅读(124)  评论(0编辑  收藏  举报

导航