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
    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    天梯赛5-12 愿天下有情人都是失散多年的兄妹 【dfs】
    poj2718 Smallest Difference【贪心】
    HDU problem 5635 LCP Array【思维】
    codeforces 782C Andryusha and Colored Balloons【构造】
    HDU 4278 Faulty Odometer【进制转换】
    codeforces B. The Meeting Place Cannot Be Changed【二分】
    POJ 3264 Balanced Lineup 【线段树】
    HDU 1850
    CodeForces-714C
    HDU Problem 1247 Hat's Words 【字典树】
  • 原文地址:https://www.cnblogs.com/L-Memory/p/7304866.html
Copyright © 2011-2022 走看看