单元最短路(非堆优化)

早期代码 、代码很烂
http://acm.hdu.edu.cn/showproblem.php?pid=2544 //基础
http://acm.hdu.edu.cn/showproblem.php?pid=1874 //基础+
http://acm.hdu.edu.cn/showproblem.php?pid=2066 //聚点

Problem - 2544 (hdu.edu.cn)
很基础的最短路径算法的题目, 注意数据的范围,做好初始化;
AC 代码:

#include<iostream>
#include<algorithm>
#include<cstring>


using namespace std;
int n,m;
const int maxn=110;
const int inf=1e9;
int d[maxn];
int t[maxn][maxn];
bool v[maxn];

void cc()
{
    for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++)
            if(i!=j) t[i][j]=inf;
    memset(v,0,sizeof(v));
    v[n]=0;
    for(int i=1;i<=n;i++) d[i]=inf;
    d[n+1]=inf;
}
void dis()
{
    int x=1;v[x]=1;d[x]=0;

    for(int k=0;k<n;k++)
    {

        for(int i=1;i<=n;i++)
        {
            if(!v[i]&&t[x][i]!=inf)
                d[i]=min(d[i],t[x][i]+d[x]);
        }
        int tx=n+1;
        for(int i=1;i<=n;i++)
            if(!v[i])
            tx=d[tx]<d[i]?tx:i;
        x=tx;
        v[tx]=1;
    }
}

int main()
{
    while(cin>>n>>m&&m!=0&&n!=0)
    {
        cc();
        int x,y,z;
        for(int i=0;i<m;i++)
        {
            cin>>x>>y>>z;
            t[x][y]=t[y][x]=z;
        }
        dis();
        cout<<d[n]<<endl;
    }
}

Problem - 1874 (hdu.edu.cn)
和上一个题难度一样,只是改了一下起点和终点的位置,至于需不需要剪支,没有测试过 ,根据数据范围来看,应该不会超限的;
不知道是不是判断平台的问题 ,没有该scanf之前 可能一直处于超限状态,最后是改t的赋值之后才对的,因为题目没说两地之间会不会有重复的道路
AC代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=210;
const int inf=1e9+1;
int d[maxn];
int t[maxn][maxn];
bool v[maxn];
int n,m,S,T;
void cc()
{
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            if(i!=j) t[i][j]=inf;
    for(int i=0;i<n;i++) v[i]=0;
    for(int i=0;i<=n;i++) d[i]=inf;
}
void dis()
{
    int x=S;v[S]=1;d[S]=0;
    for(int k=0;k<n;k++)
    {
        for(int i=0;i<n;i++)
            if(!v[i]&&t[x][i]!=inf)
                d[i]=min(d[i],t[x][i]+d[x]);
        int tx=n;
        for(int i=0;i<n;i++)
            if(!v[i])
            tx=d[tx]<d[i]?tx:i;
        if(tx==T) break;
        x=tx;
        v[x]=1;
    }
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        cc();
        int x,z,y;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            t[x][y]=t[y][x]=min(t[x][y],z);
        }
        scanf("%d%d",&S,&T);
        dis();
        if(d[T]==inf)
            printf("-1\n");
        else
            printf("%d\n",d[T]);
    }
}

Problem - 2066 (hdu.edu.cn)
很有意思的一个题目;
1.最开始想法是一次迪捷斯算法 然后从想去的地方找出最小的。喜提WA
2.之后改scanf ,
3.后面竟然还优化了一下代码的写法
if(!v[i]&&t[x][i]!=inf) d[i]=min(d[i],t[x][i]+d[x]);
直接删成 if(!v[i]) d[i]=min(d[i],t[x][i]+d[x]);
这总估计也算不上优化吧 在写法上能偷懒,但是如果数据爆的话这总写法是不可以的
4.
散->聚
聚集起点的方法不难想出来,就是设起点为0,起点到联通点的距离为0,这也是算法要实现必须要做的。
那么聚集终点捏?
也是可以的 方法同聚集起点,这样聚集终点的好处,能提前结束算法,不用迭代出0到i所有点的距离再比较要去点的大小。这种优化是非常可观的。
AC代码

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int maxn=1e3+10;
const int inf=1e6;
int t[maxn][maxn];
int d[maxn];
bool v[maxn];
int tcity[maxn];

int m,n,D;
int maxcity;

void cc1()
{
    for(int i=0;i<maxn;i++)
        for(int j=0;j<maxn;j++)
            if(i!=j) t[i][j]=inf;
    memset(v,0,sizeof(v));
    for(int i=0;i<maxn;i++) d[i]=inf;
    maxcity=0;
}

void dis()
{
    int x=0;v[x]=1;d[x]=0;
    for(int k=0;k<maxcity;k++)
    {
        for(int i=1;i<=maxcity;i++)
        {
            if(!v[i]) d[i]=min(d[i],t[x][i]+d[x]);
        }
        int tx=maxcity+1;
        for(int i=1;i<=maxcity;i++)
            if(!v[i])
            tx=d[tx]<d[i]?tx:i;
        x=tx;
        v[x]=1;
        if(x==maxcity) break;
    }
}

int main()
{
    while(~scanf("%d%d%d",&m,&n,&D))
    {
        cc1();
        int x,y,z;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            t[x][y]=t[y][x]=min(t[x][y],z);
            maxcity=max(x,max(maxcity,y));
        }
        maxcity++;
        for(int i=0;i<n;i++)
            {
                scanf("%d",&x);
                t[x][0]=t[0][x]=0;
            }
        for(int i=0;i<D;i++)
            {
                scanf("%d",&x);
                t[x][maxcity]=t[maxcity][x]=0;//聚集
            }
        dis();
        printf("%d\n",d[maxcity]);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值