【BZOJ1001】【BJOI2006】狼抓兔子

BZOJ找虐记。

这道题..一看就是最小割,关键是裸做显然超时,

那么我们该怎么做呢?

Link:http://wenku.baidu.com/view/b31cc3d6c1c708a1284a447e.html    两级相通————浅析最大最小定理在信息学竞赛中的应用 By 周冬

这个给出了关于平面图最小割转化为最短路的详细过程及证明

既然最短路,那么DJ+堆就可以到O(nlogn)了,Discuss的SPFA有人被卡有人没有

另外注意n = 1 和 m = 1 要Special Judge

题目里面倒是没有什么容易写错的。

就是开了个D数组来记每个点的对应数码...实在是懒得算了。这样子相当方便不觉得吗?不过可能会慢些就是。


ps:这大概是我AC最快的一次。三次过。第一次特判写错,第二次是空间开小了,三次就过了。

不过由于写的静态,而且为了方便写了SPFA而不是DJHeap,所以时间上其丑无比(4000ms,第一名155ms...哭瞎了)。当然代码也是。


还是把我UGLY的Code放上来...不想瞎眼的情Ctrl + W好了TAT

#include<iostream>
#include<cstdio> 
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<climits>
#define ot "%d"
#ifdef WIN32
#define otl "%I64d"
#else
#define otl "%lld"
#endif
#define Max(t, a, b) ({t _ = (a), __ = (b); _ > __ ? _ : __;})
#define min(a, b) ({int _ = (a), __ = (b); _ < __ ? _ : __;})
#define swap(a, b) ({int _ = (a); (a) = (b); (b) = _;})
#define maxp 2020055
#define maxm 1005

using namespace std;

int n, m, fin, dis[maxp], h[maxp], nt[maxp << 2], t[maxp << 2], v[maxp << 2], tot, d[2][maxm][maxm];

void link(int a, int b, int c)
{
	t[++tot] = b; nt[tot] = h[a]; v[h[a] = tot] = c;
	t[++tot] = a; nt[tot] = h[b]; v[h[b] = tot] = c;
}

void termin(int k)
{
	int s, ans = INT_MAX;
	for (int i = 1; i < k; i++) scanf(ot, &s), ans = min(s, ans);
	printf(ot, ans);
	exit(0);	
}

void init()
{
	//freopen("1.in", "r", stdin);
	//freopen("1.out", "w", stdout);
	scanf(ot ot, &n, &m);
	if (n == 1) termin(m);
	if (m == 1) termin(n);
	int t;
	fin = 0;
	for (int i = 1; i < n; ++i)
		for (int j = 1; j < m; ++j)
			d[0][i][j] = ++fin, d[1][i][j] = ++fin;
	for (int i = 1; i < n; ++i)
		d[0][i][0] = d[1][i][0] = fin + 1, d[0][i][m] = d[0][i][m] = 0;
	for (int i = 1; i < m; ++i)
		d[0][n][i] = d[1][n][i] = fin + 1, d[0][0][i] = d[1][0][i] = 0;
			
	tot = 0; ++fin;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j < m; ++j)
		{
			scanf(ot, &t);
			link(d[0][i - 1][j], d[1][i][j], t);
		}
	for (int i = 1; i < n; ++i)
		for (int j = 1; j <= m; ++j)
		{
			scanf(ot, &t),
			link(d[1][i][j - 1], d[0][i][j], t);
		}
	for (int i = 1; i < n; ++i)
		for (int j = 1; j < m; ++j)
		{
			scanf(ot, &t);
			link(d[0][i][j], d[1][i][j], t);
		}
}

bool iq[maxp];
int que[maxp + 1], head, tail;

bool relax(int a, int b, int c)
{
	if (dis[a] + c < dis[b])
	{
		dis[b] = dis[a] + c;
		if (!iq[b]) return 1;
			else return 0;
	}
	return 0;
}

void spfa()
{
	head = 0, tail = 1, que[1] = 0; dis[0] = 0;
	do
	{
		if (++head == maxp) head = 1;
		int p = que[head];
		for (int e = h[p]; e; e = nt[e])
			if (relax(p, t[e], v[e]))
			{
				if (++tail == maxp) tail = 1;
				iq[que[tail] = t[e]] = 1;
			}
		iq[p] = 0;
	} while (head != tail);
}

int main()
{
	init();
	memset(dis, 63, sizeof dis);
	spfa();
	printf("%d", dis[fin]);
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值