BZOJ1726 POJ3255 P2865: [Usaco2006 Nov]Roadblocks路障

Description
贝茜把家搬到了一个小农场,但她常常回到FJ的农场去拜访她的朋友。贝茜很喜欢路边的风景,不想那么快地结束她的旅途,于是她每次回农场,都会选择第二短的路径,而不象我们所习惯的那样,选择最短路。 贝茜所在的乡村有R(1<=R<=100,000)条双向道路,每条路都联结了所有的N(1<=N<=5000)个农场中的某两个。贝茜居住在农场1,她的朋友们居住在农场N(即贝茜每次旅行的目的地)。 贝茜选择的第二短的路径中,可以包含任何一条在最短路中出现的道路,并且,一条路可以重复走多次。当然咯,第二短路的长度必须严格大于最短路(可能有多条)的长度,但它的长度必须不大于所有除最短路外的路径的长度。
Input
* 第1行: 两个整数,N和R,用空格隔开
* 第2..R+1行: 每行包含三个用空格隔开的整数A、B和D,表示存在一条长度为 D(1 <= D <= 5000)的路连接农场A和农场B
Output
* 第1行: 输出一个整数,即从农场1到农场N的第二短路的长度
Sample Input
4 4

1 2 100

2 4 200

2 3 250

3 4 100

Sample Output
450

输出说明:

最短路:1 -> 2 -> 4 (长度为100+200=300)

第二短路:1 -> 2 -> 3 -> 4 (长度为100+250+100=450)

HINT
Source
Gold

输入:
5 5
1 2 100
2 3 100
3 4 100
4 5 100
3 5 200

输出:
600

dijkstra:
次短路的做法和最短路径基本一致,唯一的不同点在于,在求出最短路径的情况下必须要保留下次短路径。对于Dijkstra判断中取出的每一个点,如果到它的距离大于当前该点的次短距离,则当前该点已经取到最短距离和次短距离,不进行操作,否则进行两次判断:如果小于最短边,则赋给最短边,并将最短边赋给次短边;或者如果大于最短边且小于次短边,则赋给次短边。两次完成之后均要加入队列。


//没有优先队列
#include<iostream>
#include<cstdio>
#include<cstring>
#define INF 1000000007
#define MAXN 5005 
#define MAXM 222222 
using namespace std;
int n,r,u,v,w,head[MAXN],cnt;
int d[MAXN][2], e,m;   
bool vis[MAXN][2]; 

struct Edge{
    int to,next,w;
}edge[MAXM*2];

void add(int fo,int to,int cost)
{
    cnt++;
    edge[cnt].to=to;
    edge[cnt].w=cost;
    edge[cnt].next=head[fo];
    head[fo]=cnt;
}
int dijkstra(int s,int t)
{
    int flag, u;  
    memset(vis, 0, sizeof(vis));  
    for(int i=1;i<=n;i++)
        d[i][0]=d[i][1]=INF;//最短路,次短路 
    d[s][0]=0;
    for(int i=1;i<2*n;i++)
    {
        int mini=INF;
        for(int j=1;j<=n;j++)//dijkstra找最小的值,用最小值更新后面的 
        {
            if(!vis[j][0] && d[j][0]<mini)
            {
                u=j;
                flag=0;//用来记录最短路 
                mini=d[j][0];
            }
            else if(!vis[j][1] && d[j][1]<mini )
            {
                u=j;
                flag=1;//用来记录最长路 
                mini=d[j][1];
            }
        }
        if (mini == INF)  
            break;
        vis[u][flag]=1;
        for(int j=head[u];j!=-1;j=edge[j].next)
        {
            int v=edge[j].to;
            int w=edge[j].w;//该边的权植 
            if(d[v][0]>mini+w)
            {
                d[v][1]=d[v][0];
                d[v][0]=mini+w; 
            }
            else if(d[v][1]>mini+w && d[v][0]<mini+w)
                d[v][1]=mini+w;     
        }   
    }
    return d[t][1];
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(head,-1,sizeof head);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
        add(v,u,w);
    }
    printf("%d\n",dijkstra(1,n));
}

迷之错误…90分RE


90分RE:
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define INF 0x7fffffff
#define MAXN 5555
#define MAXM 100000+10
using namespace std;
int n,m,u,v,w,head[2*MAXN],cnt=0;
int dis1[2*MAXN],dis2[2*MAXN];   
struct Rec
{
    int num,len;
    bool operator < (const Rec &a) const
    {
        return len>a.len;
    }
}; 
struct Edge{
    int to,next,w;
}edge[MAXM*4];

void add(int fo,int to,int cost)
{
    cnt++;
    edge[cnt].to=to;
    edge[cnt].w=cost;
    edge[cnt].next=head[fo];
    head[fo]=cnt;
}
int dijkstra(int s,int t)
{
    priority_queue<Rec> que;      

    for(int i=2;i<=n;i++)
        dis1[i]=dis2[i]=INF;//最短路,次短路 
    dis1[s]=0;
    dis2[s]=INF;

    Rec temp;
    temp.len=0;
    temp.num=s;
    que.push(temp);

    while (!que.empty())
    {
        Rec hd=que.top();
        que.pop();

        int u=hd.num; // 
        for(int j=head[u];j!=-1;j=edge[j].next)
        {
            int v=edge[j].to;//该边连接的是哪个点 
            int w=edge[j].w;//该边的权植 

            if (hd.len+w>dis2[v]) continue;//

            else if(dis1[v]>hd.len+w)
            {
                dis2[v]=dis1[v];
                dis1[v]=hd.len+w;
                temp.len=dis1[v];
                temp.num=v;
                que.push(temp);
            }
            else if(dis1[v]<hd.len+w && dis2[v]>hd.len+w)//没有考虑到dis1[]==hd.len+w 的情况 
            {                                           //并不是上一个if之后 else就可以了 
                dis2[v]=hd.len+w;   
                temp.len=dis2[v];
                temp.num=v;
                que.push(temp); 
            }
//          cout<<temp.num<<","<<dis1[temp.num]<<","<<dis2[temp.num]<<endl;
        } 
//      cout<<endl; 
    }
    return dis2[t];
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(head,-1,sizeof head);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
        add(v,u,w);
    }
    printf("%d\n",dijkstra(1,n));
    return 0; 
}

Spfa:正着跑一边最短路,倒着跑一边最短路。那么,所有的,起点到该边一端点的距离+该边另一端点到终点的距离+该边的长度 ,取min && !=最短路。就是答案。
没有写vis[u] = 0; 这句话90分。

#include<iostream>
#include<cstdio>
#include<queue> 
#include<cstring>
#define MM 100000+10
#define MN 5100
using namespace std;

int n,m,u,v,w,cnt;
int vis[MN],dis[MN][2],head[MN];
int mn =100000007;

struct Edge{
    int to,next,value;
}edge[2*MM];

void add(int fn,int tn,int cost)
{
    cnt++;
    edge[cnt].to =tn;
    edge[cnt].next=head[fn];
    edge[cnt].value=cost;
    head[fn]=cnt;
}
void spfa(int s,int p)
{
    memset(vis,0,sizeof vis);
    queue<int> que;

    dis[s][p]=0;
    vis[s] = 1;
    que.push(s);    

    while(!que.empty() )
    {
        int u=que.front();
        que.pop();

        for(int j=head[u];j>0;j=edge[j].next)
        {
            int v=edge[j].to;
            if(dis[u][p]+edge[j].value<dis[v][p] )
            {
                dis[v][p]= dis[u][p]+edge[j].value;
                if(!vis[v])
                {
                    vis[v]=1;
                    que.push(v);
                }
            }
        }
        vis[u] = 0; 
    }
} 
int main()
{
    freopen("block.in","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
        add(v,u,w);
    }
    memset(dis,1,sizeof dis);//因为是个二维数组,不是两个数组,不需要再次赋无穷值 
    spfa(1,0);
//  memset(dis,1,sizeof dis);****!!!!!*********wrong不要在赋值,否则把之前求好的dis[][0]也变成无穷大了********
    spfa(n,1);

    for(int i=1;i<=n;i++)
    {   
        for(int j=head[i];j;j=edge[j].next)
        {
            int secdis=edge[j].value+dis[i][0]+dis[edge[j].to][1];
            if(secdis<mn && secdis>dis[n][0])//dis[n][0]是最短路长度 
                mn= secdis; 
        }
    } 
    cout<<mn<<endl; //没有写这句话90分。。 
}

http://www.cnblogs.com/iiyiyi/p/6078326.html最短路总结
http://www.cnblogs.com/iiyiyi/p/4706182.html#3659514例题
http://blog.csdn.net/fk_acm/article/details/51168613 其他博客,三种方法的代码

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值