BFS预处理出包括起点和终点以及所有水果的距离,然后状态压缩DP.
#include <stdio.h>
#include <ctime>
#include <stdlib.h>
#include <string.h>
const int N = 260;
const int M = 20;
struct node {
int x, y;
void get(int a, int b) {
x = a; y = b;
}
void write() {
printf("%d %d\n", x, y);
}
};
int n, m;
int ini[N][N];
int id[N][N];
node vaild[M];
int vlen;
bool h[N][N];
int dis[M][M];
int mv[4][2] = {{1,0}, {-1, 0}, {0, 1}, {0, -1}};
int f[18][(1<<18)];
int s[(1<<18)][18];
int slen[(1<<18)][2];
int w[M];
inline int max(int a, int b ){ return a > b ? a : b;}
void init() {
memset( id, 0, sizeof( id ));
vlen = 0;
int cnt = 0;
for(int i = 0; i < n; i ++) {
for(int j = 0; j < m; j ++) {
scanf("%d", ini[i] + j);
if( i == 0 && j == 0 ) {
vaild[vlen++].get(i, j);
id[i][j] = ++cnt;
}
else if( ini[i][j] > 0 ) {
vaild[vlen++].get(i, j);
id[i][j] = ++cnt;
}
else if( i == n-1 && j == m-1 ) {
vaild[vlen++].get(i, j);
id[i][j] = ++cnt;
}
}
}
}
node que[N*N*10];
int head, tail, flag, step;
inline void pre() {
head = tail = 0;
memset(h, 0, sizeof( h));
step = 0;
}
inline bool isok(node a) {
if( a.x < 0 || a.x >= n || a.y < 0 || a.y >= m ) return false;
if( ini[a.x][a.y] == -1 || h[a.x][a.y] ) return false;
return true;
}
inline void expand(node now) {
for(int i = 0; i < 4; i ++) {
node next;
next.get(now.x+mv[i][0], now.y+mv[i][1]);
if( isok(next) ) {
que[++tail] = next;
h[next.x][next.y] = 1;
}
}
}
void bfs() {
memset(dis, -1 ,sizeof(dis));
for(int i = 0; i < vlen; i ++) {
pre();
node ori = vaild[i];
que[++tail] = ori;
h[ori.x][ori.y] = 1;
while( head < tail ) {
int size = tail - head;
while( size -- ) {
node now = que[++head];
expand(now);
int d = id[now.x][now.y];
if( d > 0 ) dis[i][d-1] = step;
}
step ++;
}
}
}
void dp() {
if( dis[0][vlen-1] < 0 ) {
puts("you loss!");
return;
}
int mm = (1<<(vlen-1));
for(int i = 0; i < mm; i ++) for(int j = 0 ; j < vlen-1; j ++) f[j][i] = -1;
for(int i = 0; i < vlen; i ++) {
w[i] = ini[vaild[i].x][vaild[i].y];
}
for(int i = 0; i < vlen-1; i ++)
if( w[0] >= dis[0][i+1] && dis[0][i+1] >= 0) {
f[i][1<<i] = w[0] + w[i+1] -dis[0][i+1];
}
for(int i = 1; i < mm; i ++) {
int lenj = slen[i][0];
int lenk = slen[i][1];
for(int jj = 0; jj < lenj; jj ++) {
int j = s[i][jj];
if( j < vlen-1)
for(int kk = lenj; kk < lenj+lenk; kk ++) {
int k = s[i][kk];
int news = ( i|(1<<j) );
if( k<vlen-1 && f[k][i] >= dis[k+1][j+1] && dis[k+1][j+1] >= 0 ) {
f[j][i|(1<<j)] = max( f[j][i|(1<<j)], f[k][i] - dis[k+1][j+1]+ w[j+1] );
}
}
}
}
int ans = -1, t;
if( w[0] >= dis[0][vlen-1] && dis[0][vlen-1]>=0 ) ans = w[0] - dis[0][vlen-1];
for(int i = 1; i < mm; i ++){
for(int j = 0; j < vlen-1; j ++) {
t = dis[j+1][vlen-1];
if( t >= 0 && f[j][i] >= t )
ans = max(ans, f[j][i]-t);
}
}
if(w[0] == 0) ans = -1;
if( dis[0][vlen-1] == 0 ) ans = w[0];
if( ans < 0 ) puts("you loss!");
else printf("%d\n", ans);
}
void best() {
int mm = (1<<17);
for(int i = 1; i < mm; i ++) {
slen[i][0] = slen[i][1] = 0;
for(int j = 0; j < 17; j ++) if( (i & (1<<j)) == 0 ) s[i][slen[i][0]++] = j;
for(int j = 0; j < 17; j ++) if( (i & (1<<j)) != 0 ) s[i][slen[i][0]+slen[i][1]++] = j;
}
}
int main() {
best();
int tt = clock();
freopen("in.txt","r",stdin);
while( scanf("%d %d", &n, &m) != EOF) {
init();
bfs();
dp();
}
printf("%d\n", clock() - tt);
while(1);
}