【BZOJ 3049】【USACO2013 Jan】Island Travels BFS+状压DP

这是今天下午的互测题,只得了60多分

分析一下错因:

  $dis[i][j]$只记录了相邻的两个岛屿之间的距离,我一开始以为可以,后来$charge$提醒我有可能会出现来回走的情况,而状压转移就一次,无法实现来回走的情况,所以加了一个类似$floyed算法$的三重循环来更新每个点的距离,然后状态转移就可以了,枚举起点和终点,最后统计答案

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char c[53][53];
int n, m, dis[18][18], belong[53][53], f[40000][18], cnt = 0, qx[2500000], qy[2500000];
int far[2500000], head, tail;
bool vis[53][53];
inline void _(int x, int y) {
	belong[x][y] = cnt;
	vis[x][y] = 1;
	if (x > 1 && c[x - 1][y] == 'X' && !vis[x - 1][y])
		_(x - 1, y);
	if (y > 1 && c[x][y - 1] == 'X' && !vis[x][y - 1])
		_(x, y - 1);
	if (x < n && c[x + 1][y] == 'X' && !vis[x + 1][y])
		_(x + 1, y);
	if (y < m && c[x][y + 1] == 'X' && !vis[x][y + 1])
		_(x, y + 1);
}
inline void __(int x) {
	int nowx, nowy;
	while (head != tail) {
		++head; if ( head >= 2500000) head %= 2500000;
		nowx = qx[head];
		nowy = qy[head];
		if (nowx > 1 && !vis[nowx - 1][nowy] && c[nowx - 1][nowy] != '.') {
			if (c[nowx - 1][nowy] == 'S') {
				++tail; if (tail >= 2500000) tail %= 2500000;
				qx[tail] = nowx - 1;
				qy[tail] = nowy;
				far[tail] = far[head] + 1;
				vis[nowx - 1][nowy] = 1;
			} else {
				dis[x][belong[nowx - 1][nowy]] = min( dis[x][belong[nowx - 1][nowy]], far[head]);
			}
		}
		if (nowy > 1 && !vis[nowx][nowy - 1] && c[nowx][nowy - 1] != '.') {
			if (c[nowx][nowy - 1] == 'S') {
				++tail; if (tail >= 2500000) tail %= 2500000;
				qx[tail] = nowx;
				qy[tail] = nowy - 1;
				far[tail] = far[head] + 1;	
				vis[nowx][nowy - 1] = 1;			
			} else {
				dis[x][belong[nowx][nowy - 1]] = min( dis[x][belong[nowx][nowy - 1]], far[head]);
			}
		}
		if (nowx < n && !vis[nowx + 1][nowy] && c[nowx + 1][nowy] != '.') {
			if (c[nowx + 1][nowy] == 'S') {
				++tail; if (tail >= 2500000) tail %= 2500000;
				qx[tail] = nowx + 1;
				qy[tail] = nowy;
				far[tail] = far[head] + 1;
				vis[nowx + 1][nowy] = 1;
			} else {
				dis[x][belong[nowx + 1][nowy]] = min( dis[x][belong[nowx + 1][nowy]], far[head]);
			}			
		}
		if (nowy < m && !vis[nowx][nowy + 1] && c[nowx][nowy + 1] != '.') {
			if (c[nowx][nowy + 1] == 'S') {
				++tail; if (tail >= 2500000) tail %= 2500000;
				qx[tail] = nowx;
				qy[tail] = nowy + 1;
				far[tail] = far[head] + 1;
				vis[nowx][nowy + 1] = 1;
			} else {
				dis[x][belong[nowx][nowy + 1]] = min( dis[x][belong[nowx][nowy + 1]], far[head]);
			}
		}
	}
}
int main() {
	scanf("%d%d\n", &n, &m);
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j) {
			c[i][j] = getchar();
			while (c[i][j] != 'X' && c[i][j] != '.' && c[i][j] != 'S')
				c[i][j] = getchar();
		}
	memset(vis, 0, sizeof(vis));
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j)
			if (!vis[i][j] && c[i][j] == 'X') {
				++cnt;
				_(i, j);
			}
	memset(dis, 1, sizeof(dis));
	for(int i = 1; i <= cnt; ++i) {
		head = 0;
		tail = 0;
		memset(vis, 0, sizeof(vis));
		for(int k = 1; k <= n; ++k)
			for(int l = 1; l <= m; ++l)
				if (belong[k][l] == i) {
					vis[k][l] = 1;
					++tail; if ( tail >= 2500000) tail %= 2500000;
					qx[tail] = k;
					qy[tail] = l;
					far[tail] = 0;
				}
		__(i);
	}
    for(int k = 1; k <= cnt; ++k)
        for(int i = 1; i <= cnt; ++i)
            for(int j = 1; j <= cnt; ++j)
                if (dis[i][k] + dis[k][j] < dis[i][j])
                    dis[i][j] = dis[i][k] + dis[k][j];
	memset(f, 1, sizeof(f));
	int ans = 500000, tot = (1 << cnt) - 1;
	for(int i = 1; i <= cnt; ++i)
		f[1 << ( i - 1)][i] = 0;
	for(int i = 1; i <= tot; ++i) {
		for(int j = 1; 1 << (j - 1) <= i; ++j) {
			if (1 << (j - 1) & i) {
				for(int k = 1; k <= cnt; ++k)
					if (k != j && (1 << (k - 1) & i))
						f[i][j] = min(f[i][j], f[i ^ (1 << (j - 1))][k] + dis[k][j]);
			}
		}
	}
	for(int i = 1; i <= cnt; ++i)
		ans = min(ans, f[tot][i]);
	printf("%d\n",ans);
	return 0;
}

以后思维得更严谨才行

我的BFS写的就是这么丑,这又怎样?

posted @ 2016-03-29 20:01  abclzr  阅读(245)  评论(0编辑  收藏  举报