POJ 1178 Floyd

先给一个我最先写的一个代码吧。总体思路是这样的,对于每个输入的点,都进行一次广搜,打出到达其他点的最短路径(这个效率相比于floyd太低了)再加在ans数组当中,最后搜索出最小值,并输出。虽然这个代码能过很多数据,但是 Discuss 里A1A2A3H2H5H6H7H8C1C2C5C6C7E2E3E4E5E6E7E8 就过不了。

至于原因还望大牛们给予指点。我预测可能是广搜有问题,我原以为,用广搜打出的路径表一定就严格递增的,所以我就这么写了,不过后来还是有问题,望各位指点啊。

我的错误代码如下:

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <queue>

using namespace std;

#define LEN 8
#define MIN(a,b) (a<b?a:b)

int ans[LEN][LEN];
int king[LEN][LEN];
int knight[LEN][LEN];
int flag[LEN][LEN];
int count = 0;
int point[8][2] = {
	{-1, -2},{-1, 2},{1, -2},{1, 2},
	{-2, -1},{-2, 1},{2, -1},{2, 1}
};

/*
void find(int x, int y, int n) {
	if(x < 0 || x >= LEN || y < 0 || y >= LEN) {
		return;
	}
	if(count > 128) return;
	count++;
	knight[x][y] = MIN(knight[x][y], n+1);
	find(x-1, y-2, knight[x][y]);
	find(x-1, y+2, knight[x][y]);
	find(x+1, y-2, knight[x][y]);
	find(x+1, y+2, knight[x][y]);
	find(x-2, y-1, knight[x][y]);
	find(x-2, y+1, knight[x][y]);
	find(x+2, y-1, knight[x][y]);
	find(x+2, y+1, knight[x][y]);
}
*/

int _abs(int a) {
	return a < 0 ? (-a) : (a);
}

void find(int sx, int sy) {
	queue<int> queue;
	while(!queue.empty()) {
		queue.pop();
	}
	queue.push(sx);
	queue.push(sy);
	queue.push(0);
	flag[sx][sy] = 1;
	while(!queue.empty()) {
		int x = queue.front();
		queue.pop();
		int y = queue.front();
		queue.pop();
		int n = queue.front();
		queue.pop();
		for(int i = 0; i < 8; i++) {
			int xx = x+point[i][0];
			int yy = y+point[i][1];
			if(xx < 0 || xx >= LEN || yy < 0 || yy >= LEN) {
				continue;
			}
			if(flag[xx][yy]) {
				continue;
			}
			flag[xx][yy] = 1;
			knight[xx][yy] = n+1;
			queue.push(xx);
			queue.push(yy);
			queue.push(n+1);
		}
	}
}

void init() {
	for(int i = 0; i < LEN; i++) {
		for(int j = 0; j < LEN; j++) {
			knight[i][j] = 99999;
		}
	}
	knight[0][0] = 0;
}

void pr() {
	for(int i = 0; i < LEN; i++) {
		for(int j = 0; j < LEN; j++) {
			cout<< ans[i][j]<< " ";
		}
		cout<< endl;
	}
	cout<< endl;
}

void pri() {
	for(int i = 0; i < LEN; i++) {
		for(int j = 0; j < LEN; j++) {
			cout<< knight[i][j]<< " ";
		}
		cout<< endl;
	}
	cout<< endl;
}

int main() {
	char str[10000];
	int index, i, j, k;
	memset(king, 0, sizeof(king));
	memset(flag, 0, sizeof(flag));
	init();
	king[0][0] = 0;
	for(i = 1; i < LEN; i++) {
		king[0][i] = king[0][i-1] + 1;
		king[i][0] = king[i-1][0] + 1;
	}
	for(i = 1; i < LEN; i++) {
		for(j = 1; j < LEN; j++) {
			king[i][j] = MIN(king[i][j-1], MIN(king[i-1][j], king[i-1][j-1])) + 1;
		}
	}

	while(gets(str)) {
		memset(ans, 0, sizeof(ans));
		int k1 = str[0]-'A';
		int k2 = str[1]-'0'-1;
		for(i = 0; i < LEN; i++) {
			for(j = 0; j < LEN; j++) {
				ans[i][j] += _abs(king[i][j]-king[k1][k2]);
			}
		}
//		pr();
		for(index = 2; str[index] != '\0'; index += 2) {
			int t1 = str[index]-'A';
			int t2 = str[index+1] - '0' - 1;

			memset(knight, 0, sizeof(knight));
			memset(flag, 0, sizeof(flag));
			find(t1, t2);
//			pri();
			for(i = 0; i < LEN; i++) {
				for(j = 0; j < LEN; j++) {
					ans[i][j] += _abs(knight[i][j]-knight[t1][t2]);
				}
			}
//			pr();
		}
		int min = 99999;
		for(i = 0; i < LEN; i++) {
			for(j = 0; j < LEN; j++) {
				min = MIN(min, ans[i][j]);
			}
		}
		printf("%d\n", min);
		memset(str, 0, sizeof(str));
	}
	return 0;
}


正确的 DP + floyd 解法, 其实最主要的就是把原来的那个 map 转换成为一个新的二维数组。

A1A2A3H2H5H6H7H8C1C2C5C6C7E2E3E4E5E6E7E8
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
#define MAX 8
const int INF = (1<<20);
int dirKing[8][2] = {{1,0},{-1,0},{0,1},{0,-1},{1,1},{-1,-1},{1,-1},{-1,1}};
int dirKnight[8][2] = {{-2,-1},{-2,1},{2,-1},{2,1},{-1,-2},{1,-2},{-1,2},{1,2}};

char str[MAX*MAX*2+5];
int king[MAX*MAX][MAX*MAX], knight[MAX*MAX][MAX*MAX];
int step[MAX*MAX], num;

inline int min(int a,int b)
{
    return a < b ? a : b;
}

void init()
{
    for(int i = 0; i < MAX*MAX; ++i)
        for(int j = 0; j < MAX*MAX; ++j)
            king[i][j] = knight[i][j] = (i == j ? 0 : INF);
    for(int i = 0; i < MAX*MAX; ++i)
    {
        int x = i/8;
        int y = i%8;
        for(int j = 0; j < 8; ++j)
        {
            int xx = x+dirKing[j][0];
            int yy = y+dirKing[j][1];
            if(xx >= 0 && xx < MAX && yy >= 0 && yy < MAX)
                king[i][8*xx+yy] = 1;
        }
        
        for(int j = 0; j < 8; ++j)
        {
            int xx = x+dirKnight[j][0];
            int yy = y+dirKnight[j][1];
            if(xx >= 0 && xx < MAX && yy >= 0 && yy < MAX)
                knight[i][8*xx+yy] = 1;
        }
    }
}

void floyd(int a[][MAX*MAX])
{
    for(int k = 0; k < MAX*MAX; ++k)
    {
        for(int i = 0; i < MAX*MAX; ++i)
        {
            for(int j = 0; j < MAX*MAX; ++j)
            {
                if(a[i][j] > a[i][k]+a[k][j])
                    a[i][j] = a[i][k]+a[k][j];
            }
        }
    }
}

int main()
{
//    freopen("input.txt","r",stdin);
    init();
    floyd(king);
    floyd(knight);
    
    while(scanf("%s",str) != EOF)
    {
        int start = (str[0]-'A') + (str[1]-'1')*8;
        int num = (strlen(str)-2)/2;
        if(num == 0)
        {
            printf("0\n");
            continue;
        }
        
        for(int i = 0, j = 2; i < num; ++i, j+=2)
            step[i] = (str[j]-'A') + (str[j+1]-'1')*8;
        int result = INF;
        int t1, t2;
        int sum;
        for(int i = 0; i < MAX*MAX; ++i)
        {
            sum = 0;
            for(int k = 0; k < num; ++k)
                sum += knight[ step[k] ][i];
            for(int j = 0; j < MAX*MAX; ++j)
            {
                t1 = king[start][j];
                t2 = INF;
                for(int kk = 0; kk < num; ++kk)
                {
                    t2 = min(t2,knight[ step[kk] ][j] + knight[j][i] - knight[ step[kk] ][i]); 
                }
                result = min(result,sum+t1+t2);
            }
        }
        printf("%d\n",result);
    }
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值