第3题:跳舞鸡
【题目描述】
从前有只鸡喜欢跳舞。为了跳出最美丽的舞蹈,它发明了一种机器。这个机器有N*N个格子。一个格子要么写着’+’,’-‘,要么写着0-9的数字。并且保证每个符号的上下左右四个方向都是数字,每个数字的上下左右四个方向都是符号。这样的机器有个神奇的功能:从一个写着数字的格子出发,每次走到一个相邻的格子,把走过格子的字符按先后顺序从左到右排过来,那么可以构成一个计算式。这只鸡决定当跳到当计算式的答案等于某个值的时候就停止。但是这只鸡的IQ实在太低了,它发现怎么跳也跳不完……于是让你帮它求一个最短的路径出来。如果有多种方案,输出字典序最小的那一个(注意’+’,’-’也要计入字典序的比较)。
输入数据保证有解。
【输入格式】
第一行一个正整数T,代表有T组数据。
对于每组数据,第一行两个正整数N和C。然后接下来N行是一个N*N的矩阵,代表这个机器的样子。矩阵过后一行是C个正整数,代表每次要达到的值L。
【输出格式】
对每组数据,输出C行字符串,为达到每个给出的值所需的最短且字典序最小的计算式。
【数据范围】
对于30分的数据,N小于等于10。C小于等于20。L小于等于50。
对于100分的数据,N小于等于20,T小于等于6。C小于等于50。L大于等于1小于等于250。
【输入样例】
2
5 3
2+1-2
+3-4+
5+2+1
-4-0-
9+5+1
20 30 40
3 2
2+1
+4+
5+1
2 20
【输出样例】
1+5+5+9
3+4+5+9+9
4+9+9+9+9
2
5+5+5+5
因为要求最短路,但是又要保证路径中的权值为定值,所以考虑拆点,把一个点拆成750个点(-250~500),表示走到(i,j),且值为k,所需要的最短路径,因为要找出所有路径中的最优解,所以要加超级源,省略这个过程,直接把所有点入队,可以起到相同的效果。
至于方案,用字符串记录,如果更新最短路,同时更新方案,如果新路等于最短路,则比较方案,取字典序较小的。
输出的时候枚举所有点且值为dem[i]的,找到最短的,同时比较方案字典序。、
奇葩的是,我用string比用字符数组快得多,同时代码复杂度小很多,字符数组调试了两个小时才对,但是string就很容易写对了。。string也有它的优势,尤其是比较和在字符串后面加字符,应该学会取舍。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <string>
using std::cout;
using std::min;
using std::string;
struct node
{
long x;
long y;
long v;
bool o;
};
node que[2000010];
const long qmod = 2000000;
bool hash[30][30][800];
string g[30][30][800];
const long dx[] = {-1,0,1,0};
const long dy[] = {0,-1,0,1};
long dist[30][30][800];
char map[30][30];
node u,v;
long n;
long dem[60];
long maxc = 0;
long getint()
{
long rs=0;bool sgn=1;char tmp;
do tmp = getchar();
while (!isdigit(tmp)&&tmp-'-');
if (tmp == '-'){tmp=getchar();sgn=0;}
do rs=(rs<<3)+(rs<<1)+tmp-'0';
while (isdigit(tmp=getchar()));
return sgn?rs:-rs;
}
void spfa()
{
long l = 0;
long r = 0;
memset(dist,0x3f,sizeof dist);
for (long i=1;i<n+1;i++)
for (long j=1;j<n+1;j++)
{
if (isdigit(map[i][j]))
{
r ++;
que[r].x = i;
que[r].y = j;
que[r].v = (map[i][j] - '0');
dist[i][j][map[i][j]-'0'+260] = 0;
g[i][j][map[i][j]-'0'+260] = map[i][j];
que[r].o = true;
}
}
while (l < r)
{
l ++;
if (l == qmod)
l = 0;
u = que[l];
hash[u.x][u.y][u.v+260] = false;
for (long i=0;i<4;i++)
{
v = u;
v.x += dx[i];
v.y += dy[i];
if (v.x<1||v.y<1||v.x>n||v.y>n)
continue;
if (isdigit(map[v.x][v.y]))
v.v = u.o?v.v+(map[v.x][v.y]-'0'):v.v-(map[v.x][v.y]-'0');
else
v.o = map[v.x][v.y]=='+';
if (v.v > 500 || v.v < -250)
continue;
if (dist[v.x][v.y][v.v+260] >= dist[u.x][u.y][u.v+260] + 1)
{
if (dist[v.x][v.y][v.v+260] > dist[u.x][u.y][u.v+260] + 1)
{
dist[v.x][v.y][v.v+260] = dist[u.x][u.y][u.v+260] + 1;
g[v.x][v.y][v.v+260] = g[u.x][u.y][u.v+260]+map[v.x][v.y];
}
else
g[v.x][v.y][v.v+260] = min(g[v.x][v.y][v.v+260],g[u.x][u.y][u.v+260]+map[v.x][v.y]);
if (!hash[v.x][v.y][v.v+260])
{
r ++;
que[r] = v;
hash[v.x][v.y][v.v+260] = true;
}
}
}
}
}
int main()
{
freopen("dance.in","r",stdin);
freopen("dance.out","w",stdout);
long T = getint();
n = 0;
while (T --)
{
memset(hash,0,sizeof hash);
memset(dist,0,sizeof dist);
for (long i=0;i<30;i++)
for (long j=0;j<30;j++)
for (long k=0;k<800;k++)
g[i][j][k][0] = g[i][j][k][0] = 'z';
n = getint();
long c = getint();
for (long i=1;i<n+1;i++)
for (long j=1;j<n+1;j++)
{
do map[i][j] = getchar();
while (!isdigit(map[i][j])&&map[i][j]!='-'&&map[i][j]!='+');
}
maxc = 0;
for (long i=1;i<c+1;i++)
{
dem[i] = getint();
if (dem[i] > maxc)
maxc = dem[i];
}
spfa();
for (long k=1;k<c+1;k++)
{
string path = "";
long mind = 0x3f3f3f3f;
for (long i=1;i<n+1;i++)
{
for (long j=1;j<n+1;j++)
{
if (dist[i][j][dem[k]+260] < mind)
{
mind = dist[i][j][dem[k]+260];
path = g[i][j][dem[k]+260];
}
else if (dist[i][j][dem[k]+260]==mind)
path = min(path,g[i][j][dem[k]+260]);
}
}
cout << path << std::endl;
}
}
return 0;
}