POJ 3463 Sightseeing (最短路&次短路条数问题)

题意:给一个有向图,求从s到f 的最短路+最短路-1的条数。   有重边。


分析: 代码是根据挑战的次短路改编的。      具体请看代码。



#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<cctype>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<iomanip>
#include<sstream>
#include<limits>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const ll INF = 1e18;
const int maxn = 2e5+10;
const ll MOD = 1000000007;
const double EPS = 1e-10;
const double Pi = acos(-1.0);

struct edge{int to,cost;};
//typedef pair<int,int>P; //1 dist 2 u
struct P{
    int first,second,z;   //z 标志是最短路还是次短路
    P(int a=0,int b=0,int c=0):first(a),second(b),z(c){}
    bool operator < (const P &rhs)const{return first>rhs.first;}
};
int V;
vector<edge>G[maxn];
int d[maxn],d2[maxn],cnt1[maxn],cnt2[maxn],vis[maxn][2];  //d cnt1 最短路长度及数量 d2 cnt2 次短路长度及数量  vis代表有没访问过
void dij(int s)
{
    priority_queue<P >que;
    fill(d,d+V+1,inf);
    fill(d2,d2+V+1,inf);
    d[s] = 0;
    cnt1[s] = 1;
    que.push(P(0,s,0));
    while(!que.empty())
    {
        P p = que.top(); que.pop();
        int v = p.second, z = p.z;
        if (d2[v] < p.first || vis[v][z]) continue;
        vis[v][z] = 1;       //一定要记录是否访问过,不然会出错,因为是单调队列。
        for(int i = 0; i < G[v].size();i++)
        {
            edge e = G[v][i];
            int temp = p.first + e.cost;

            if (d[e.to] > temp)  // 比最短路短
            {
                d2[e.to] = d[e.to];
                d[e.to] = temp;
                cnt2[e.to] = cnt1[e.to];
                cnt1[e.to] = z==0? cnt1[v]:cnt2[v];   //要弄清楚等于哪个。

                que.push(P(d[e.to] ,e.to,0));
                que.push(P(d2[e.to] ,e.to,1));
            }else
              if (d[e.to] == temp) cnt1[e.to] += z==0? cnt1[v]:cnt2[v];   // 等于最短路
              else
                if (temp < d2[e.to])   // 比次短路短
                {
                    d2[e.to] = temp;
                    cnt2[e.to] = z==0? cnt1[v]:cnt2[v];
                    que.push(P(d2[e.to] ,e.to,1));
                }else if (temp == d2[e.to]) cnt2[e.to] += z==0? cnt1[v]:cnt2[v];  // 等于次短路
        }
    }
}
int main(){
#ifdef LOCAL
	freopen("C:\\Users\\lanjiaming\\Desktop\\acm\\in.txt","r",stdin);
	//freopen("output.txt","w",stdout);
#endif
//ios_base::sync_with_stdio(0);
     int T,n,m;
     scanf("%d",&T);
     while(T--)
     {
         scanf("%d%d",&n,&m);
         for(int  i = 0; i <= n; i++) G[i].clear();
         V = n;
         for(int i = 0; i < m; i++)
         {
             int a,b,l;
             scanf("%d%d%d",&a,&b,&l);
             G[a].push_back(edge{b,l});
         }
         int s,f;
         scanf("%d%d",&s,&f);
         memset(cnt1,0,sizeof cnt1);
         memset(cnt2,0,sizeof cnt2);
         memset(vis,0,sizeof vis);
         dij(s);

         if (d[f] == d2[f]-1) cnt1[f] += cnt2[f];
         printf("%d\n",cnt1[f]);
     }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#define MAXVEX 30 #define MAXCOST 1000 void prim(int c[MAXVEX][MAXVEX],int n) /*己知图的顶点为{1,2,...,n},c[i][j]和c[j][i]为边(i,j)的权,打印最小生成树 的每条边*/ { int i,j,k,min,lowcost[MAXVEX],closest[MAXVEX];; for (i=2;i<=n;i++) /*从顶点1开始*/ { lowcost[i]=c[1][i]; closest[i]=1; } closest[1]=0; for (i=2;i<=n;i++) /*从U之外求离U中某一顶点最近的顶点*/ { min=MAXCOST; j=1;k=i; while (j<=n) { if (lowcost[j]<min && closest[j]!=0) { min=lowcost[j]; k=j; } j++; } printf("(%d,%d) ",closest[k],k); /*打印边*/ closest[k]=0; /*k加入到U中*/ for (j=2;j<=n;j++) if (closest[j]!=0 && c[k][j]<lowcost[j]) { lowcost[j]=c[k][j]; closest[j]=k; } } } main() { int n=7,i,j,mx[MAXVEX][MAXVEX]; for (i=0;i<=n;i++) for (j=0;j<=n;j++) mx[i][j]=MAXCOST; mx[1][2]=50; mx[1][3]=60; mx[2][4]=65; mx[2][5]=40; mx[3][4]=52; mx[3][7]=45; mx[4][5]=50; mx[5][6]=70; mx[4][6]=30; mx[4][7]=42; printf("最小生成树边集:\n "); prim(mx,n); } 数据结构导学上的, /*克鲁斯卡尔算法构造最小生成树*/ #define MAXEDGE 30 /*MAXEDGE为最大的边数*/ struct edges /*边集类型,存储一条边的起始顶点bv、终止顶点tv和权w*/ { int bv,tv,w; }; typedef struct edges edgeset[MAXEDGE]; int seeks(int set[],int v) { int i=v; while (set[i]>0) i=set[i]; return(i); } kruskal(edgeset ge,int n,int e) /*ge表示的图是按权值从小到大排列的*/ { int set[MAXEDGE],v1,v2,i,j; for (i=1;i<=n;i++) set[i]=0; /*给set中的每个元素赋初值*/ i=1; /*i表示待获取的生成树中的边数,初值为1*/ j=1; /*j表示ge中的下标,初值为1*/ while (j<n && i<=e) /*按边权递增顺序,逐边检查该边是否应加入到生成树中*/ { v1=seeks(set,ge[i].bv); /*确定顶点v所在的连通集*/ v2=seeks(set,ge[i].tv); if (v1!=v2) /*当v1,v2不在同一顶点集合,确定该边应当选入生成树*/ { printf("(%d,%d) ",ge[i].bv,ge[i].tv); set[v1]=v2; j++; } i++; } } main() { int n=7,e=10; edgeset mx; mx[1].bv=4;mx[1].tv=6;mx[1].w=30; mx[2].bv=2;mx[2].tv=5;mx[2].w=40; mx[3].bv=4;mx[3].tv=7;mx[3].w=42; mx[4].bv=3;mx[4].tv=7;mx[4].w=45; mx[5].bv=1;mx[5].tv=2;mx[5].w=50; mx[6].bv=4;mx[6].tv=5;mx[6].w=50; mx[7].bv=3;mx[7].tv=4;mx[7].w=52; mx[8].bv=1;mx[8].tv=3;mx[8].w=60; mx[9].bv=2;mx[9].tv=4;mx[9].w=65; mx[10].bv=5;mx[10].tv=6;mx[10].w=70; printf("最小生成树边集:\n "); kruskal(mx,n,e); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值