zoukankan      html  css  js  c++  java
  • bzoj 2763: [JLOI2011]飞行路线

    2763: [JLOI2011]飞行路线

    2017-09-15


    Description

    Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在n个城市设有业务,设这些城市分别标记为0到n-1,一共有m种航线,每种航线连接两个城市,并且航线有一定的价格。Alice和Bob现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多k种航线上搭乘飞机。那么Alice和Bob这次出行最少花费多少?

    Input

    数据的第一行有三个整数,n,m,k,分别表示城市数,航线数和免费乘坐次数。
    第二行有两个整数,s,t,分别表示他们出行的起点城市编号和终点城市编号。(0<=s,t<n)
    接下来有m行,每行三个整数,a,b,c,表示存在一种航线,能从城市a到达城市b,或从城市b到达城市a,价格为c。(0<=a,b<n,a与b不相等,0<=c<=1000)
     

    Output 

    只有一行,包含一个整数,为最少花费。

    Sample Input

    5 6 1
    0 4
    0 1 5
    1 2 5
    2 3 5
    3 4 5
    2 3 3
    0 2 100

    Sample Output

    8

    HINT 

    对于30%的数据,2<=n<=50,1<=m<=300,k=0;

    对于50%的数据,2<=n<=600,1<=m<=6000,0<=k<=1;s:暴力枚举就能过这部分spfa

    对于100%的数据,2<=n<=10000,1<=m<=50000,0<=k<=10.


    有没有k不都是最短路嘛,之前感觉好复杂,分层图?不就是在普通的spfa的基础上加一个k的循环跑最短路,保证每一次跑spfa都是在删去i条边最短.多几重队列维护

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #define ll long long
    #include<queue>
    using namespace std;
    const int maxn=10000+999;
    const int maxm=50000+999;
    const int INT=1e9+7;
    int read(){
        int an=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while('0'<=ch&&ch<='9'){an=an*10+ch-'0';ch=getchar();}
        return an*f;
    }
    int n,spf[15][maxn],m,k,star,fin,cnt,ans,f[maxn];
    queue<int>q[15];
    bool vis[15][maxn];
    struct saber{
    int nex,to,wi;
    }b[maxm<<1]; 
    void add(int x,int y,int z){
        cnt++;
        b[cnt].nex=f[x];
        b[cnt].to=y;
        b[cnt].wi=z;
        f[x]=cnt;
    }
    void spfa(){
        spf[0][star]=0;
        vis[0][star]=1;q[0].push(star);
        for(int i=0;i<=k;i++)
            while(!q[i].empty()){
            int x=q[i].front();vis[i][x]=0;
            q[i].pop();
            for(int j=f[x];j;j=b[j].nex){
                int v=b[j].to;
            if(spf[i][v]>spf[i][x]+b[j].wi){
                spf[i][v]=spf[i][x]+b[j].wi;
                if(!vis[i][v]){
                    q[i].push(v);
                    vis[i][v]=1;}//不用spell_card 
                }
            if(spf[i+1][v]>spf[i][x]){
                spf[i+1][v]=spf[i][x];
                if(!vis[i+1][v]){
                q[i+1].push(v);    
                vis[i+1][v]=1;}//用spell_card 
                }
            }
        }
    ans=spf[k][fin];
    }
    int main(){
        for(int i=0;i<=11;i++)
            for(int j=0;j<=maxn-999;j++)spf[i][j]=INT;
        n=read();m=read();k=read();
        star=read();fin=read();
        for(int i=1;i<=m;i++){
            int x,y,z;
            x=read();y=read();z=read();
            add(x,y,z);
            add(y,x,z);
        }
        spfa();
        printf("%d",ans);
        return 0;
    }
    spell_card

    by:s_a_b_e_r


     分层图?拆点?我也不知道叫什么啊

    感觉很玄学的一个题啊(笑)

    “所谓分层图就是有多维状态的有边长图,然后比起正常的最短路转移就是多了一种跨维度转移的状态转移。”
    说的好,但是什么意思啊。_(:зゝ∠)_
    大意就是把原图复制成好几层,每层既有能连本层的边,也有能连到下一层的边,这样的一个图(集)。

    于是这个题,把整个图复制成k+1层,同层连无向边,向上一层连权值为0的有向边
    d[i][j]表示从起点到第i点,用了j次免费次数所耗费的的最小费用。
    然后就跑一波最短路啊……spfa或者heap-dijkstra都行啊……

    ——关于处理异层边的问题
    事实上根本不用开大边集数组来存边啦……
    每次同层转移的时候多判断一下到k+1的情况就完全OK

    #include<iostream>
    #include<cstdio>
    #include<queue>
    using namespace std;
    const int M=50005,N=10005;
    int n,m,k,s,t,d[N][11],p[N],cnt;
    bool in[N][11];
    struct node{
        int num,f;
    };
    queue<node>q;
    struct edge{
           int to,next,val;
    }e[M<<1];
    void add(int u,int v,int w)
    {
         ++cnt;
         e[cnt].val=w;
         e[cnt].to=v;
         e[cnt].next=p[u];
         p[u]=cnt;
    }
    int main()
    {
        scanf("%d%d%d%d%d",&n,&m,&k,&s,&t);
        for(int i=1;i<=m;++i)
        {
           int a,b,c;
           scanf("%d%d%d",&a,&b,&c);
           add(a,b,c);
           add(b,a,c);
        }
        for(int i=0;i<=n-1;++i)
          for(int j=0;j<=k;++j)
            d[i][j]=2147483647;
        d[s][0]=0;
        q.push((node){s,0});
        while(!q.empty())
        {
          node x=q.front();q.pop();
          int u=x.num,f=x.f;
          in[u][f]=false;
          int l=p[u];
          while(l)
          {
            int v=e[l].to;
            if(d[v][f]>d[u][f]+e[l].val)
            {
              d[v][f]=d[u][f]+e[l].val;
              if(!in[v][f])
              {
                q.push((node){v,f});
                in[v][f]=true;
              }
            }
            if(f<k)
            if(d[v][f+1]>d[u][f])
            {
              d[v][f+1]=d[u][f];
              if(!in[v][f+1])
              {
                q.push((node){v,f+1});
                in[v][f+1]=true;
              }
            }
            l=e[l].next;
          }
        }
        cout<<d[t][k]<<endl;
        return 0;
    }
    bzoj 2763

    by:wypx


     s:真的在飞啊飞行路线

    w:这样飞也不收钱啊

  • 相关阅读:
    [设计模式]在CodeDom代码生成中使用Decorator模式实现类型创建
    【翻译】防腐层:面向领域驱动设计的更为稳健的系统集成方案
    EntityFramework之领域驱动设计实践【后续篇】:基于EF 4.3.1 Code First的领域驱动设计实践案例
    Apworks框架中各种仓储实现的性能基准测试与结果对比
    CQRS架构中同步服务的一种实现方式
    在Visual Studio 2010中创建多项目(解决方案)模板【三】
    Microsoft NLayerApp案例理论与实践 应用层
    在Visual Studio 2010中创建多项目(解决方案)模板【二】
    小猫奥斯卡
    测试一下又拍网图片外链
  • 原文地址:https://www.cnblogs.com/ck666/p/7524714.html
Copyright © 2011-2022 走看看