cogs 2. 旅行计划 dijkstra+打印路径小技巧

2. 旅行计划

★★   输入文件:djs.in   输出文件:djs.out   简单对比
时间限制:3 s   内存限制:128 MB

【题目描述】

过暑假了,阿杜准备出行旅游,他已经查到了某些城市的两两之间的距离及可行路线(可行路线有方向),如下图所示。请你编程计算从阿杜所住城市到其它城市的最短路径以帮助阿杜制定旅行计划。

【输入格式】

输入由若干行组成,第一行有三个整数 n(1n100) 为城市数,m(1mn2) 为城市间道路数,s(0sn1) 是阿杜所住城市。第 2 至 m+1 行是每条路的信息,每行三个整数,为道路的起点、终点和两城市间距离。(城市从 0 开始编号)

【输出格式】

输出 n 组(按城市编号由小至大),每组三行

第一行:城市编号及一个冒号

第二行:path及一个冒号,后面是最短路径节点编号序列(编号间用一个空格隔开)

第三行:cost及一个冒号,后面是一个整数,表示路径距离

如果没有通路则输出 no

【输入样例】

6 8 0
0 2 10
0 4 30
0 5 100
1 2 5
2 3 50
3 5 10
4 3 20
4 5 60

【输出样例】

0:
no
1:
no
2:
path:0 2
cost:10
3:
path:0 4 3
cost:50
4:
path:0 4
cost:30
5:
path:0 4 3 5
cost:60
   自动选择评测机   gcc/g++4.8.5gcc/g++4.8.5 -O2gcc/g++4.8.5(C++11)gcc/g++4.6.3gcc/g++4.6.3 -O2         

 
提交代码 Pascal C C++

看到评论区的一群大佬的评论 我立刻不淡定了  决定来瞅瞅(探头探脑   这一道据说很坑的题 没想到想了3分钟 敲了4分钟 完美AC!

 

那么这一道题到底应该咋做

我的时间复杂度是(mlogm  +  n^2)n<100  m<10000  这个时间复杂度看起来还是 很棒的

 

首先很简单 我们要来按照题目中给出的单向边和起点 跑一遍dijkstra  这是O(n)的

然后重点在于怎样输出路径

 

在之前的时候总是看到别人的代码里有一个非常神奇的数组是path  然而我并没有学过这么难的东西(俺可是初学者--哈哈)

首先我们最暴力的想法肯定是O(n^3)的

对于每一个点 从剩下的点里面 看一下哪一个点是他的前驱

很显然这一道题n^3也没啥问题

但是蒟蒻拒绝!

所以我们想办法压缩到O(n^2)

听起来不错

 

既然我们浪费时间主要在找前驱  那么我们只需要在dijkstra的过程中顺便用一个pathpre数组来存每一个点的前驱  后面直接跑一个递归调用一下下就好啦

具体看代码 还是非常好理解的优化(这是蒟蒻自己发明的!请求专利)

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define pa pair<int,int>
#define maxn 115
using namespace std;
int n,m,s;
int dis[maxn],vis[maxn],pathpre[maxn];
vector<int> v[maxn],w[maxn];
priority_queue< pa,vector<pa>,greater<pa> > q;
inline int read()
{
    int X=0; bool flag=1; char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
    while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
    if(flag) return X;
    return ~(X-1);
}
inline void write(int X)
{
    if(X<0) {X=~(X-1); putchar('-');}
    if(X>9) write(X/10);
    putchar(X%10+'0');
}
void Dijkstra()
{
    memset(dis,0x3f,sizeof(dis));
    dis[s]=0;
    q.push(make_pair(0,s));
    while(!q.empty()){
        int rt=q.top().second;
        q.pop();
        if(vis[rt]) continue;
        vis[rt]=1;
        for(int i=0;i<v[rt].size();i++){
            int to=v[rt][i];
            if(dis[to]>dis[rt]+w[rt][i]){
                dis[to]=dis[rt]+w[rt][i];
                pathpre[to]=rt;
                q.push(make_pair(dis[to],to));
            }
        }
    }
}
bool flagfinish=false; 
void path_out(int rt){//最差时间复杂度:O(mlogm+n^2) 
    if(rt==s){
        write(rt);printf(" ");
        flagfinish=true;
        return;
    }
    //    for(int i=0;i<v[rt].size();i++)
        //    if(dis[v[rt][i]]==dis[rt]+w[rt][i]){   错 
    //            path_out(v[rt][i]);
    //            write(rt);printf(" ");
    //            return;
    //        }
    path_out(pathpre[rt]);write(rt);printf(" ");
}
int main()
{
    freopen("djs.in","r",stdin);
    freopen("djs.out","w",stdout);
    n=read(),m=read(),s=read();
    for(int i=1,x,y,z;i<=m;i++)
    {
        x=read(),y=read(),z=read();
        v[x].push_back(y);w[x].push_back(z);
    }    
    Dijkstra();
    for(int i=0;i<n;i++)
    {
        write(i);puts(":");
        if(dis[i]==inf||i==s) puts("no");
        else
        {
            printf("path:");path_out(i);printf("\n");
            printf("cost:%d\n",dis[i]);flagfinish=false;
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/Tidoblogs/p/11456459.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是将代码修改为cot平滑的方法: 1. 首先,需要使用边界角的cot权重计算每个顶点的权重。 2. 然后,使用cot权重对每个顶点的邻域点进行加权计算,得到平滑后的坐标。 3. 最后,根据平滑后的坐标更新每个顶点的位置。 修改后的代码如下: float smooth() { float err = -1; cogs.clear(); v_end = mesh.vertices_end(); //cot平滑 for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it) { cog[0] = cog[1] = cog[2] = weight_sum = 0.0; for (vv_it = mesh.vv_iter(*v_it); vv_it.is_valid(); ++vv_it) { double cot_weight = 0.0; MyMesh::HalfedgeHandle heh = mesh.find_halfedge(*v_it, *vv_it); if (!mesh.is_boundary(heh)) { MyMesh::HalfedgeHandle prev_heh = mesh.prev_halfedge_handle(heh); MyMesh::HalfedgeHandle next_heh = mesh.next_halfedge_handle(heh); MyMesh::VertexHandle prev_vh = mesh.to_vertex_handle(prev_heh); MyMesh::VertexHandle next_vh = mesh.to_vertex_handle(next_heh); MyMesh::Point prev_p = mesh.point(prev_vh); MyMesh::Point curr_p = mesh.point(*v_it); MyMesh::Point next_p = mesh.point(next_vh); double cot_alpha = cot(prev_p - curr_p, next_p - curr_p); double cot_beta = cot(curr_p - prev_p, next_p - prev_p); cot_weight = cot_alpha + cot_beta; } cog += cot_weight * mesh.point(*vv_it); weight_sum += cot_weight; } cogs.push_back(cog / weight_sum); } for (v_it = mesh.vertices_begin(), cog_it = cogs.begin(); v_it != v_end; ++v_it, ++cog_it) { if (!mesh.is_boundary(*v_it)) { MyMesh::Point p = mesh.point(*v_it); err = max(err, (p - *cog_it).norm()); mesh.set_point(*v_it, *cog_it); } } return err; } 其中cot函数的定义如下: double cot(MyMesh::Point a, MyMesh::Point b) { return dot(a, b) / cross(a, b).norm(); } 注意,这里使用的是边界角的cot权重,因此在计算cot权重时需要判断当前边是否为边界。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值