POJ 1124 Oh, Those Achin' Feet

127 篇文章 0 订阅
22 篇文章 0 订阅

http://acm.pku.edu.cn/JudgeOnline/problem?id=1124

/*
    利用DFS回溯求所有最短路径(最短路径可能不止一条)
    行走的时候只有当下一个点是终点或者下一点是街道时才可以继续走到下一个点
    注意剪枝
    注意entrance/exit不参与load,只有街道参与load,即最终结果里凡是非街道结点都要输出0
    */
#include <iostream>
#include <map>
#include <string>
#include <memory>
#define MAX_N 20
#define QSIZE 500
using namespace std;

char graph[MAX_N + 1][MAX_N + 1]; //记录输入的图
double res[MAX_N + 1][MAX_N + 1]; //记录最终的结果,即每个街道的load值
int pre[MAX_N + 1][MAX_N + 1][2]; //记录每个结点前驱的坐标
int vTime[MAX_N + 1][MAX_N + 1];  //记录在找一对entrance和exit之间最短路径时,路径上每个点出现的次数,用于计算每个点需要分到的load值
int pos[MAX_N + 1][2];            //记录每个entrance/exit的坐标,index是:当前字符 - 'A'
bool v[MAX_N + 1][MAX_N + 1];     //DFS时标识这个点是否被访问过,访问时置1,回溯时置0


int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; //遍历的四个方向

map<string, int> load;            //记录输入里每个entrance/exit对的load总和,对于AB 2 BA 1,要把BA转换成AB,所以最终是AB 3
map<string, int>::iterator itr;

int rowN, colN, srcR, srcC, destR, destC, pathNum, minLen; //计算时用到的相关变量

string temp;

//判断当前点是否可走
bool inRange(int curR, int curC)
{
    char type = graph[curR][curC];
    //是否在坐标轴内
    bool t1 = (curR >= 1 && curR <= rowN && curC >= 1 && curC <= colN);
    //是否是终点或者是街道,否则不可走
    bool t2 = ((curR == destR && curC == destC) || type == '.');
    return t1 && t2;
}
void dfs(int curR, int curC, int len)
{
    int d, nextR, nextC, tR, tC;
    if(curR == destR && curC == destC)
    {
        //超过了当前最短的,直接忽略掉
        if(len > minLen)
            return;
        //新的路径更短
        else if(len < minLen)
        {
            //重置数据
            memset(vTime, 0, sizeof(vTime));
            pathNum = 1;
        }
        //路径长度和最优的相等,则路径数增加1
        else
            pathNum++;
        minLen = len;
               
        //遍历路径,为每个节点的load比重加1
        nextR = pre[curR][curC][0];
        nextC = pre[curR][curC][1];
        while(!(nextR == srcR && nextC == srcC))
        {
            vTime[nextR][nextC]++;
            tR = pre[nextR][nextC][0];
            tC = pre[nextR][nextC][1];
            nextR = tR, nextC = tC;
        }
        return;
    }
    //剪枝
    if(len >= minLen)
        return;
   
    //遍历四个方向
    for(d = 0; d < 4; d++)
    {
        nextR = curR + dir[d][0], nextC = curC + dir[d][1];
        //判断是否可走
        if(v[nextR][nextC] || !inRange(nextR, nextC)) continue;
        v[nextR][nextC] = true;
        pre[nextR][nextC][0] = curR, pre[nextR][nextC][1] = curC;
        //继续走
        dfs(nextR, nextC, len + 1);
        //回溯
        v[nextR][nextC] = false;
       
    }
}

//利用DFS遍历所有的entrance/exit对找出所有的最短路径,并按照比例对相同的最短路径上的几点进行load均分
void travel()
{
    int lVal, i, j;
    for(itr = load.begin(); itr != load.end(); itr++)
    {
        //相关初始化
        temp = itr->first;
        lVal = itr->second;
        srcR = pos[temp[0] - 'A'][0], srcC = pos[temp[0] - 'A'][1];
        destR = pos[temp[1] - 'A'][0], destC = pos[temp[1] - 'A'][1];
        memset(v, 0, sizeof(v));
        memset(vTime, 0, sizeof(vTime));
        pre[srcR][srcC][0] = -1;
        v[srcR][srcC] = true;
        pathNum = 0;
        minLen = INT_MAX;

        //遍历
        dfs(srcR, srcC, 0);

        //按照各点的比重均分
        for(i = 1; i <= rowN; i++)
        {
            for(j = 1; j <= colN; j++)
                res[i][j] += ((double)vTime[i][j] / pathNum) * lVal;
        }
    }
}
int main()
{
    int i, j, l;
    char c;
    //输入格式化
    cin>>colN>>rowN;
    for(i = 1; i <= rowN; i++)
        for(j = 1; j <= colN; j++)
        {
            cin>>c;
            graph[i][j] = c;
            if(c >= 'A' && c <= 'O')
            {
                pos[c - 'A'][0] = i;
                pos[c - 'A'][1] = j;
            }
        }
    while(cin>>temp>>l && temp != "XX")
    {
        if(temp[0] > temp[1])
        {
            c = temp[0];
            temp[0] = temp[1];
            temp[1] = c;
        }
        itr = load.find(temp);
        if(itr == load.end())
            load[temp] = l;
        else
            load[temp] += l;
    }
    //遍历
    travel();
    //输出结果
    for(i = 1; i <= rowN; i++)
    {
        for(j = 1; j <= colN; j++)
        {
            //保留小数点后两位,进行四舍五入
            double temp = res[i][j];
            int t = temp * 1000 + 5;
            t = t / 10 * 10;
            temp = (double)t / 1000;
            printf("%7.2f", temp);
        }
        printf("/n");
    }
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值