ccf 2017 12 - 4 行车路线

 

 

 

 

 

附上代码:

 

#include<stdio.h>
#include<string.h>
#define inf 0x7fffffff
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int MAXM = 1e6 + 5;
int n, m;
typedef struct NODE
{
    int to;
    ll temp;
    ll cost;
    int ff;
    friend bool operator < (const NODE &a, const NODE &b) {
        return a.cost > b.cost;
    }
}node;
typedef struct Edge
{
    int from;///起点
    ll temp;///记录权值
    int f;///标记小路
    int next;
    int to;
    ll w;
} edge;
edge maps[MAXM];
int head[505];
ll dist[505];
int vids[505];
int cnt;
void creat ()
{
    for(int i=0; i<505; i++)
        head[i]=-1;
    cnt=0;
}
void add(int t,int u,int v,ll w)
{
    maps[cnt].f = t;
    maps[cnt].from = u;
    maps[cnt].to=v;
    maps[cnt].w=w;
    maps[cnt].next=head[u];///一开始放置为-1,-1的条件就可以跳出
    ///下一步接着储存,head[u]的值,就是前面的位置
    head[u]=cnt++;///head[u]会得到这条线的值
}
ll dijkstra(int s,int t)
{
    for(int i=0; i<505; i++)
    {
        vids[i]=0;
        dist[i]=inf;
    }
    priority_queue<node>que;
    node begins;
    begins.to = s;
    begins.temp = 0;
    begins.cost = 0;
    begins.ff = 0;
    que.push(begins);
    while(!que.empty())
    {
        node ends=que.top();
        que.pop();
        if(!vids[ends.to])
        {
            vids[ends.to]=1;
            dist[ends.to]=ends.cost;
            for(int i = head[ends.to]; ~i; i = maps[i].next)
            {
                int to = maps[i].to;
                ll w = maps[i].w;
                int flag = maps[i].f;
                if(!vids[to])
                {
                    node ans;
                    ans.to=to;
                    if(ends.ff == 0 && flag == 0)
                    {
                        ans.cost = ends.cost + w;
                        ans.ff = flag;
                        ans.temp = 0;
                    }
                    else if(ends.ff == 1 && flag == 0)
                    {
                        ans.cost = ends.cost + w;
                        ans.ff = flag;
                        ans.temp = 0;
                    }
                    else if(ends.ff == 1 && flag == 1)
                    {
                        ans.cost = ends.cost - (ends.temp * ends.temp) + (ends.temp + w) * (ends.temp + w);
                        ans.ff = flag;
                        ans.temp = ends.temp + w;
                    }
                    else if(ends.ff == 0 && flag == 1)
                    {
                        ans.cost = ends.cost + (w * w);
                        ans.ff = flag;
                        ans.temp = w;
                    }
                    que.push(ans);
                }
            }
        }
    }
    if(dist[t] == inf)
    {
        return -1;
    }
    else
    {
        return dist[t];
    }
}
int main()
{
   while(~scanf("%d%d",&n, &m))
   {
       creat();
       int t, a, b;
       long long c;
       for (int i = 0; i < m; i ++) {
           scanf("%d%d%d%lld",&t, &a, &b, &c);
           add(t, a, b, c);
           add(t, b, a, c);
       }
       ll re = dijkstra(1, n);
       printf("%lld\n",re);
   }
    return 0;
}

 

#include <iostream>
#include <queue>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long LL;
class Edge{
public:
    Edge(){}/*无参构造函数 */
public:
    int u, v, w, next, flag;
    /* u - 起点
       v - 终点
       w - 边权
       next - 同个起点的前一条边
       flag - 标记是否是小路
    */
};
class Malash_map{
public:
    Malash_map(){
    }
    void Init(){
        for(int i = 0; i < 505; i ++){
            head[i] = -1;
        }
        tot = 0;
    }//初始化链式前向星
    void add(int u, int v, int w, int flag){//添加一条单向边
        arr[tot].u = u, arr[tot].v = v, arr[tot].w = w, arr[tot].flag = flag;
        arr[tot].next = head[u], head[u] = tot ++;
    }
public:
    int head[505], tot;
    Edge arr[int(2e5 + 500)];
};//链式前向星
int vids[505];//标记这个点是否已经被拓展过
LL dist[505];//从1到n这个点的最短路径
Malash_map M;
class Node{
public:
    Node(int _v, int _f, LL _min_d, LL _cost):v(_v), f(_f), min_dist(_min_d), cost(_cost){}
    friend bool operator< (const Node &a, const Node &b){
        return a.cost > b.cost;
    }//将小于号重载于大于号,那么就能保证优先队列维护的是较小的路径先出队列
public:
    int v, f;
    LL min_dist, cost;
};
LL dijkstra(int s, int t){
    for(int i = 0; i < 505; i ++){
        vids[i] = 0, dist[i] = __LONG_LONG_MAX__;
    }//初始化,肯定所有的点没有被访问过,所有的距离都是无穷远
    priority_queue<Node>que;//优先队列,维护较短的路径先出队列
    while(!que.empty()) que.pop();//清空优先队列
    Node begins(s, 0, 0, 0);//构造起点
    que.push(begins);//将起点放入优先队列
    while(!que.empty()){
        Node temp = que.top();
        que.pop();//取出对应的优先队列中的第一个点,即当前到某个点的最短路径
        if(vids[temp.v] == 1){//如果这个点被拓展过,那么证明这个点的最短路径
        //以及以这个点为起点的边肯定都被拓展过,那么就没有必要再拓展一次
            continue;
        }
        vids[temp.v] = 1;//标记这个点已经被拓展
        dist[temp.v] = min(dist[temp.v], temp.cost);//保留路径最小值
        if(temp.v == t){//如果已经找到了终点,那么没有必要再去拓展了
        //拓展其他都没有必要,所以可以剪枝做一个小优化,直接返回结果
            return dist[t];
        }
        for(int i = M.head[temp.v]; i != -1; i = M.arr[i].next){
            //开始拓展以temp.v为起点的所有相邻边,然后构造出对应的Node新点
            Node en(M.arr[i].v, M.arr[i].flag, temp.min_dist, temp.cost);
            if(!vids[en.v]){//如果这个新点没有被走过,即没有拓展出最短路径
            //那么这个点就应该被拓展
                if((temp.f == 0 || temp.f == 1) && en.f == 0){
                    //考虑从大路->大路,小路->大路,处理的结果都是一样的如下
                    en.min_dist = 0, en.cost += M.arr[i].w;
                    //将现在连续走的小路的总数变为0,然后更新对应的cost花费
                }
                else{
                    en.cost = en.cost - (en.min_dist * en.min_dist) + (en.min_dist + M.arr[i].w) * (en.min_dist + M.arr[i].w); 
                    //假设连续走了的小路和为(a + b + c)
                    //那么又走了段小路d
                    //那么将前面得到的cost - (a + b + c)的平方 + (a + b + c + d)的平方,得到的是到当前的点的最小值
                    //然后更新练习走了的小路的和为(a + b + c + d)
                    en.min_dist += M.arr[i].w;
                }
                que.push(en);//将得到的点放入优先队列,优先队列会保证每次取出优先队列中最小的点,进行拓展。
            }
        }
    }
    return dist[t];//返回答案
}
int main(){
    int n, m;
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    while(cin >> n >> m){
        M.Init();
        for(int i = 0; i < m; i ++){
            int f, u, v, w;
            cin >> f >> u >> v >> w;
            M.add(u, v, w, f);//添加双向边
            M.add(v, u, w, f);
        }
        LL ans = dijkstra(1, n);
        cout << ans << endl;
    }
    return 0;
}

 

posted @ 2018-09-20 20:01  moxin0509  阅读(358)  评论(0编辑  收藏  举报