zoukankan      html  css  js  c++  java
  • 最短路

    1.

    /*
    这道题很容易想到二分最大的电话线长度 然后最重要的就是验证
    当边权大于我们二分的答案时候就让边权为1 跑最短路 d[n]与k比较
    数组开大点!!!! 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    
    #define M 30007
    
    using namespace std;
    int n,m,ans,tot,cnt,k;
    int head[M],ao[M],d[M],q[M];
    bool inq[M];
    struct edge
    {
        int u,to,dis,next;
    
    }e[M];
    
    inline void add(int u,int to,int dis)
    {
        e[++cnt].u=u;e[cnt].to=to;e[cnt].dis=dis;e[cnt].next=head[u];head[u]=cnt;
    }
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    void spfa()
    {
        queue<int>q;
        memset(inq,0,sizeof inq);
        memset(d,127/2,sizeof d);
        d[1]=0;q.push(1);inq[1]=true;
        while(!q.empty())
        {
            int x=q.front();q.pop();inq[x]=false;
            for(int i=head[x];i!=-1;i=e[i].next)
            {
                int v=e[i].to;
                if(d[v]>d[x]+ao[i])
                {
                    d[v]=d[x]+ao[i];
                    if(!inq[v]) q.push(v),inq[v]=true;
                }
            }
        }
    }
    
    bool Check(int x)
    {
        for(int i=1;i<=n;i++)
          for(int j=head[i];j!=-1;j=e[j].next)
          {
                  if(e[j].dis>x) ao[j]=1;
                  else ao[j]=0;
          }
          spfa();
          return d[n]<=k;
    }
    
    void solve()
    {
        int l=0,r=1000007;
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(Check(mid)) r=mid;
            else l=mid+1;
        }
        if(r==1000007) printf("-1");
        else printf("%d
    ",r);
    }
    
    int main()
    {
        memset(head,-1,sizeof head);
        int x,y,z;
        n=read();m=read();k=read();
        for(int i=1;i<=m;i++)
        {
            x=read();y=read();z=read();
            add(x,y,z);add(y,x,z);
        }
        solve();
        return 0;
    }
    洛谷P1948

     2.

    /*
    先跑最短路记录边的编号
    枚举最短路上的边,删掉跑spfa
    ans取大 
    */ 
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    #define N 1007
    #define M 1000007
    
    using namespace std;
    int n,m,ans,cnt,s,f,tot;
    bool inq[M];
    int head[M],q[M],dis[N],pre[N];//数组们开大些 
    struct edge
    {
        int u,to,next,dis;
    }e[M];
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    inline void add(int u,int to,int dis)
    {
        e[++cnt].u=u;e[cnt].to=to;e[cnt].dis=dis;
        e[cnt].next=head[u];head[u]=cnt;
    }
    
    void spfa(int flag)
    {
        int he=0,tail=0;
        memset(inq,0,sizeof inq);
        memset(q,0,sizeof q);
        for(int i=1;i<=n;i++) dis[i]=0x7f7f7f7f;//dis初值一定要搞大!!! 
        q[tail++]=s;inq[s]=true;dis[s]=0;
        while(he<=tail)
        {
            int x=q[he++];inq[x]=false;
            for(int i=head[x];i;i=e[i].next)
            {
                int v=e[i].to;
                if(dis[v]>dis[x]+e[i].dis)
                {
                    dis[v]=dis[x]+e[i].dis;
                    if(!flag) pre[e[i].to]=i;//第一次spfa 
                    if(!inq[v]) inq[v]=1,q[tail++]=v;
                }
            }
        }
    }
    
    int main()
    {
        int x,y,z;
        n=read();m=read();s=1,f=n;
        for(int i=1;i<=m;i++)
        {
            x=read();y=read();z=read();
            add(x,y,z);add(y,x,z);
        }
        spfa(0);
        int ans=0;
        for(int i=pre[n];i;i=pre[e[i].u])
        {
            int tmp=e[i].dis;
            e[i].dis=0x7f7f7f7f;
            spfa(1);
            e[i].dis=tmp;
            ans=max(ans,dis[n]);
        }
        printf("%d
    ",ans);
        return 0;
        return 0;
        return 0;
    }
    洛谷P1186

     3.

    /*
    先用向量求出三个点中的直角点,然后通过确定位置后的已知三点坐标计算第四点。
    直接暴力循环把火车和飞机的边一块存了...
    飞机场编号如下:
    City1:1 2 3 4
    City2: 5 6 7 8
    …… 由观察可知,飞机场编号(t)与城市编号(n)的关系为n=((t-1) div 4) +1.
    */
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    int t,n,st,ed,hd,tl,cnt,x[105][5],y[105][5],vet[200005],Next[200005],head[200005],q[1000005],w[1005];
    bool vis[1005];
    double dis[1005],value[200005],ans;
    
    double calc(int x1,int y1,int x2,int y2)
    {
        return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
    }
    
    void add(int a,int b,double c)
    {
        vet[++cnt]=b;
        value[cnt]=c;
        Next[cnt]=head[a];
        head[a]=cnt;
    }
    
    void spfa(int st)
    {
        hd=tl=1;
        for (int i=1; i<=n*4; i++)
        {
            dis[i]=1e9;
            vis[i]=false;
        }
        dis[st]=0;
        q[1]=st;
        vis[st]=true;
        while (hd<=tl)
        {
            int u=q[hd];
            for (int i=head[u]; i; i=Next[i])
            {
                int v=vet[i];
                if (dis[v]>dis[u]+value[i])
                {
                    dis[v]=dis[u]+value[i];
                    if (!vis[v])
                    {
                        vis[v]=true;
                        q[++tl]=v;
                    }
                }
            }
            hd++;
            vis[u]=false;
        }
    }
    
    int main()
    {
        int cas;
        scanf("%d",&cas);
        while (cas--)
        {
            memset(head,0,sizeof(head));
            scanf("%d%d%d%d",&n,&t,&st,&ed);
            for (int i=1; i<=n; i++)
            {
                scanf("%d%d%d%d%d%d%d",&x[i][1],&y[i][1],&x[i][2],&y[i][2],&x[i][3],&y[i][3],&w[i]);
                if ((y[i][1]-y[i][2])*(y[i][3]-y[i][2])==(x[i][2]-x[i][1])*(x[i][3]-x[i][2]))
                {
                    x[i][4]=(x[i][1]+x[i][3]-x[i][2]);
                    y[i][4]=(y[i][1]+y[i][3]-y[i][2]);
                }
                if ((y[i][2]-y[i][1])*(y[i][3]-y[i][1])==(x[i][2]-x[i][1])*(x[i][1]-x[i][3]))
                {
                    x[i][4]=(x[i][2]+x[i][3]-x[i][1]);
                    y[i][4]=(y[i][2]+y[i][3]-y[i][1]);
                }
                if ((y[i][1]-y[i][3])*(y[i][2]-y[i][3])==(x[i][1]-x[i][3])*(x[i][3]-x[i][2]))
                {
                    x[i][4]=(x[i][1]+x[i][2]-x[i][3]);
                    y[i][4]=(y[i][1]+y[i][2]-y[i][3]);
                }
            }
            for (int i=1; i<=n; i++)
              for (int j=1; j<=4; j++)
                for (int k=j+1; k<=4; k++)
                {
                    add((i-1)*4+j,(i-1)*4+k,w[i]*calc(x[i][j],y[i][j],x[i][k],y[i][k]));
                    add((i-1)*4+k,(i-1)*4+j,w[i]*calc(x[i][j],y[i][j],x[i][k],y[i][k]));
                }
            for (int i=1; i<=n; i++)
              for (int j=1; j<=4; j++)
                for (int p=i+1; p<=n; p++)
                    for (int q=1; q<=4; q++)
                    {
                        add((i-1)*4+j,(p-1)*4+q,t*calc(x[i][j],y[i][j],x[p][q],y[p][q]));
                        add((p-1)*4+q,(i-1)*4+j,t*calc(x[i][j],y[i][j],x[p][q],y[p][q]));
                    }
            ans=1e9;
            for (int i=1; i<=4; i++)
            {
                spfa(4*(st-1)+i);
                for (int j=1; j<=4; j++)
                    ans=min(ans,dis[4*(ed-1)+j]);
            }
            printf("%.1lf
    ",ans);
        }
        return 0;
    }
    洛谷P1027

     4.

    /*
    目的地为起点一遍spfa
    目的地为终点n-1遍spfa
    答案取和的最大值 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    #define inf 999999999
    #define N 10007
    #define M 100007
    
    using namespace std;
    int head[M],di[N],d[N],q[N<<1];
    bool inq[N<<1];
    int n,m,cnt,ans,s,num;
    
    struct edge
    {
        int u,to,next,dis;
    }e[M];
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    inline void add(int u,int to,int dis)
    {
        e[++cnt].u=u;e[cnt].to=to;e[cnt].dis=dis;
        e[cnt].next=head[u];head[u]=cnt;
    }
    
    void spfa(int s)
    {
        int he=0,tail=0;
        for(int i=1;i<=n;i++) d[i]=inf;
        memset(inq,0,sizeof inq);
        memset(q,0,sizeof q);
        q[tail++]=s;inq[s]=true;d[s]=0;
        while(he<=tail)
        {
            int u=q[he++];inq[u]=false;
            for(int i=head[u];i;i=e[i].next)
            {
                int v=e[i].to;
                if(d[v]>d[u]+e[i].dis)
                {
                    d[v]=d[u]+e[i].dis;
                    if(!inq[v]) inq[v]=true,q[tail++]=v;
                }
            }
        }
    }
    
    int main()
    {
        int y,l,f;
        n=read();m=read();s=read();
        for(int i=1;i<=m;i++)
        {
            y=read();l=read();f=read();
            add(y,l,f);
        }
        spfa(s);
        for(int i=1;i<=n;i++) di[i]=d[i];
        for(int i=1;i<=n;i++)
        {
            if(i==s) continue;
            spfa(i);
            if(d[s]+di[i]>ans && di[i]!=inf) 
              ans=d[s]+di[i];
        }
        printf("%d
    ",ans);
        return 0;
        return 0;
        return 0;
    }
    codevs1992

     5

    /*
    这道题可以将删边操作转化为加边操作
    先将所有要删的边标记。不管他们做一次floyed。
    在倒叙添加一条边,更新答案,每次是o(n^2)的操作。
    注意floyed思想运用 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    #define N 207
     
    using namespace std;
    int a[N][N],n,m,x,y,v;
    struct node
    {
        int x,y,v,ans;
    }q[N];
    
    void floyd1()
    {
        for(int k=1;k<=n;k++)
          for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
              if(a[i][j]>a[i][k]+a[k][j])
                a[i][j]=a[i][k]+a[k][j];
        
        for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
            q[m].ans+=a[i][j];        
    }
    
    void floyd2()
    {
        for(int i=m;i>=1;i--)
        {
            x=q[i].x;y=q[i].y;v=q[i].v;
            for(int j=1;j<=n;j++)
              for(int k=1;k<=n;k++)
              {
                  if(a[j][k]>a[j][x]+a[y][k]+v)
                    a[j][k]=a[j][x]+a[y][k]+v;
              }
              for(int j=1;j<=n;j++)
                for(int k=1;k<=n;k++)
                  q[i-1].ans+=a[j][k];
        }    
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
            scanf("%d",&a[i][j]);
            
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&q[i].x,&q[i].y);
            q[i].v=a[q[i].x][q[i].y];
            a[q[i].x][q[i].y]=1000000000;
        }
        
        floyd1();floyd2();
        
        for(int i=1;i<=m;i++)
          if(q[i].ans>=1000000000) printf("INF
    ");
          else printf("%d
    ",q[i].ans);
          return 0;
    }
    codevs2011

     6.

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    #define N 360 
    
    using namespace std;
    int a[N][N],x,y,t,z,n,m;
    
    int main()
    {
        scanf("%d%d%d",&n,&m,&t);
        memset(a,0x7f,sizeof a);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            a[x][y]=z;
        }
        for(int k=1;k<=n;k++)
          for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
              a[i][j]=min(a[i][j],max(a[i][k],a[k][j]));
        for(int i=1;i<=t;i++)
        {
            scanf("%d%d",&x,&y);
            if(a[x][y]==2139062143) printf("-1
    ");
            else printf("%d
    ",a[x][y]);
        }
        return 0;
    }
    P2888

     7

    /*
    分层图最短路
    核心思想是我也不知道
    大概就是d[i][j]表示到i这个点用j条边权为0的最短路
    每次更新的时候先更新当前边不设免费道路的,在更新设最短路的。
    最后答案取小。因为啊,若可以设k条免费道路,有一条路径长度小于k,那d[n][k]可能不是正确答案
    以为d[][k]表示一定设了k条免费道路嘛~ 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    #define N 10001
    #define M 100001
    
    using namespace std;
    int head[N],d[N][11],q[M][2];
    bool inq[N][11];
    int n,m,k,st,ed,cnt;
    struct edge
    {
        int u,to,dis,next;
    }e[M];
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    inline void add(int u,int to,int dis)
    {
        e[++cnt].to=to;e[cnt].dis=dis;e[cnt].next=head[u];head[u]=cnt;
    }
    
    void spfa()
    {
        memset(d,127/3,sizeof d);
        int he=0,ta=1;
        q[0][0]=st;q[0][1]=0;
        inq[st][0]=1;d[st][0]=0;
        while(he!=ta)
        {
            int now=q[he][0],tmp=q[he++][1];inq[now][tmp]=0;
            if(he==100001) he=0;
            for(int i=head[now];i;i=e[i].next)
            {
                int v=e[i].to;
                if(d[v][tmp]>d[now][tmp]+e[i].dis)
                {
                    d[v][tmp]=d[now][tmp]+e[i].dis;
                    if(!inq[v][tmp])
                    {
                        q[ta][0]=v;q[ta++][1]=tmp;
                        inq[v][tmp]=1;
                        if(ta==100001) ta=0;
                    }
                }
                if(d[v][tmp+1]>d[now][tmp] && tmp<k)
                {
                    d[v][tmp+1]=d[now][tmp];
                    if(!inq[v][tmp+1])
                    {
                        inq[v][tmp+1]=1;
                        q[ta][0]=v;q[ta++][1]=tmp+1;
                        if(ta==100001) ta=0;
                    }
                }
            }
        }
        int ans=0x7fffffff;
        for(int i=0;i<=k;i++) ans=min(ans,d[ed][i]);
        printf("%d",ans);
    }
    
    int main()
    {
        int x,y,z;
        n=read();m=read();k=read();
        st=read();ed=read();
        while(m--)
        {
            x=read();y=read();z=read();
            add(x,y,z);add(y,x,z);
        }
        spfa();
        return 0;
    }
    bzoj2763
    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    55. 跳跃游戏
    45. 跳跃游戏 II
    对称的二叉树
    字符型图片验证码,使用tensorflow实现卷积神经网络,进行验证码识别CNN
    python版本升级及pip部署方法
    Two Sum [easy] (Python)
    工作中常用的linux命令(持续更新)
    PAT-1001. 害死人不偿命的(3n+1)猜想 (15)
    C++二维数组的动态声明
    19. Remove Nth Node From End of List(C++,Python)
  • 原文地址:https://www.cnblogs.com/L-Memory/p/7304866.html
Copyright © 2011-2022 走看看