您的位置:首页 > 其它

ural 1930. Ivan's Car

2015-08-26 00:14 519 查看
题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1930

题意描述:给定n个城镇以及m条道路,每条道路连接两个城镇,道路有上下两种状态,求起点到终点需要的最少转换状态次数;

思路大致是两种方向分开考虑,更新一个点的状态时引入方向因素;

struct共有两种:Node城镇,里面包含上下两种状态的道路指向的城镇编号,以及按各种状态到达此节点需要转换状态的次数;

Event更新信号,包含要更新的节点编号、更新方向、和最新距离(用于后期检测);

大致步骤:起点节点的距离设置0,构造Event更新信号压入优先队列;

每次取队列里距离最小的Event更新信号,用于双向更新邻接节点,有更新则该邻接节点构造更新信号入队;

队空时退出循环,输出结果;

这次代码很繁杂很凌乱,想了很久,思路不是很直观清晰,甚至用的算法都不是熟知的一些经典算法,而是憋了许久才出来的模型;

放上来只是为了纪念在这道题上流过的汗水,请各位路过的大神批评指正;

上AC代码:

//#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <stdio.h>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <map>
using namespace std;

const int NAL = 9999999;       // 不可达距离
const int UP = 0;
const int DOWN = 1;

struct Node{                    // 城镇节点,存储上下双方向邻接城镇和双方向距离
vector<int>town[2];
int dis[2];
Node() {
dis[0] = dis[1] = NAL;
town[0].clear();
town[1].clear();
}
};

struct Event{          // 更新信号,存储虚更新的节点编号、有效方向和入队时距离
int index;
int dire;
int dis;

bool operator<(Event a)const{ return dis>a.dis; }
};

void func(){
int n, m;
scanf("%d%d", &n, &m);

vector<Node>v(n);

int src, tar;
for (int i = 0; i < m; i++){
scanf("%d%d", &src, &tar);
src--; tar--;
v[src].town[0].push_back(tar);
v[tar].town[1].push_back(src);
}

scanf("%d%d", &src, &tar);
src--; tar--;
v[src].dis[0] = v[src].dis[1] = 0;

Event e;
e.index = src;
e.dire = UP;
e.dis = 0;

priority_queue<Event>q;
q.push(e);
e.dire = DOWN;
q.push(e);               // 压入src节点的双方向更新信号

while (!q.empty()){

e = q.top(); q.pop();
int dire = e.dire;
int dis = e.dis;
src = e.index;

if (v[src].dis[dire] < dis)continue;   // 证明该距离再次被其它节点更新

dis = v[src].dis[dire];
//if (src == tar)break;

vector<int> &vSrc = v[src].town[dire];  //更新同方向节点信息
for (size_t i = 0; i < vSrc.size(); i++){
int tmpTar = vSrc[i];
if (v[tmpTar].dis[dire] == NAL || v[tmpTar].dis[dire] > dis){
v[tmpTar].dis[dire] = dis;
e.index = tmpTar;
q.push(e);
}
}

dire = (dire + 1) & 1;
dis++;
vector<int>&vTar = v[src].town[dire];  // 更新反方向节点信息
for (size_t i = 0; i < vTar.size(); i++){
int tmpTar = vTar[i];
if (v[tmpTar].dis[dire] == NAL || v[tmpTar].dis[dire]>dis){
v[tmpTar].dis[dire] = dis;
e.index = tmpTar;
e.dis = dis;
e.dire = dire;
q.push(e);
}
}

}

int ans = v[tar].dis[0];
if (ans > v[tar].dis[1])ans = v[tar].dis[1];

printf("%d\n", ans);

}

int main(){

//freopen("out.txt", "w", stdout);
//freopen("in.txt", "r", stdin);

func();

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: