您的位置:首页 > 其它

USACO2013 island travels

2015-08-23 11:48 225 查看
题意:一个R行C列的矩阵,'X'表示地,'S'表示浅水,'.'表示不能走的深水。连通的X视为一个岛(不超过15个)。现在要走完所有岛,求最少的踩在浅水格子的次数。

题解:岛屿不超过15个,明显的暗示可以用状态压缩DP跑旅行商问题。但是这题需要较多的预处理。首先给每个X连通块标上岛屿的序号,然后对每一个岛屿,将它直接相邻的浅水格子压入队列跑BFS即可求出所有岛屿到他的距离。然后记得一定要跑一次Floyd!!DP的状态定义为f[s, i]表示经过了的岛屿的集合为s,最后到达i的最少路径长。

考试的时候犯了很SB的两个错误,说明写代码的时候思路不清晰。以后最好写一个函数就检查一个。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define Min(a,b) ((a)<(b)?(a):(b))
#define inmap(x,y) (x>0 && y>0 && x<=R && y<=C)
const int MAXN = 105;
const int dd[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
int N, R, C;
int dis[20][20];
char sea[MAXN][MAXN];
int cnt;
const int INF = 0x3f3f3f3f;

#define code(x,y) ((x-1)*C+y)
#define getx(s) ((s-1)/C+1)
#define gety(s) ((s-1)%C+1)
void mark(int x, int y)
{
queue<int> Q;
Q.push(code(x,y));
++cnt;
while (!Q.empty()) {
x = getx(Q.front());
y = gety(Q.front());
sea[x][y] = cnt;
Q.pop();
for (int i = 0; i<4; ++i) {
int tx = x+dd[i][0], ty = y+dd[i][1];
if (inmap(tx,ty) && sea[tx][ty]=='X')
Q.push(code(tx, ty));
}
}
}

int step[MAXN][MAXN];
void BFS(int id)
{
int i, j, k, x, y, tx, ty;
queue<int> Q;
memset(step, 0, sizeof step);
for (i = 1; i<=R; ++i)
for (j = 1; j<=C; ++j)
if (sea[i][j] == id)
for (k = 0; k<4; ++k) {
tx = i+dd[k][0], ty = j+dd[k][1];
if (inmap(tx,ty) && sea[tx][ty]=='S')//考试的时候居然忘记判断是否是浅水就直接入队了!!
Q.push(code(tx, ty)), step[tx][ty] = 1;
}
while (!Q.empty()) {
x = getx(Q.front()), y = gety(Q.front());
Q.pop();
for (i = 0; i<4; ++i) {
tx = x+dd[i][0], ty = y+dd[i][1];
if (!inmap(tx,ty)) continue;
if (sea[tx][ty]=='S' && !step[tx][ty])
Q.push(code(tx,ty)), step[tx][ty] = step[x][y]+1;
else if (1<=sea[tx][ty] && sea[tx][ty]<=cnt && sea[tx][ty]!=id) {
j = sea[tx][ty];
dis[id][j] = Min(dis[id][j], step[x][y]),
dis[j][id] = dis[id][j];
}
}
}
}

void Floyd()//考试的时候忘记加floyd了,以后一定要注意这些细节。
{
for (int k = 1; k<=cnt; ++k)
for (int i = 1; i<=cnt; ++i)
for (int j = 1; j<=cnt; ++j)
dis[i][j] = Min(dis[i][j], dis[i][k] + dis[k][j]);
}

int f[(1<<16)+1][16];
int ans = INF;
void DoDP()
{
memset(f, 0x3f, sizeof f);
int s, s1, i, j;
for (i = 1; i<=cnt; ++i)
f[1<<(i-1)][i] = 0;
for (s = 1; s < (1<<cnt); ++s)
for (i = 1; i<=cnt; ++i)
{
if (!(s&(1<<(i-1)))) continue;
s1 = s ^ (1<<(i-1));
for (j = 1; j<=cnt; ++j)
{
if (!(s1&(1<<(j-1)))) continue;
f[s][i] = Min(f[s][i], f[s1][j]+dis[j][i]);
}
}
for (i = 1; i<=cnt; ++i)
ans = Min(ans, f[(1<<cnt)-1][i]);
}

int main()
{
int i, j;
scanf("%d%d", &R, &C);
memset(dis, 0x3f, sizeof dis);
for (i = 1; i<=R; ++i)
scanf("%s", sea[i]+1);
for (i = 1; i<=R; ++i)
for (j = 1; j<=C; ++j)
if (sea[i][j] == 'X')
mark(i, j);
for (i = 1; i<=cnt; ++i)
BFS(i);
Floyd();
DoDP();
printf("%d\n", ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bfs dp oi