最短路

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\n",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\n",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\n",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\n",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\n");
      else printf("%d\n",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\n");
        else printf("%d\n",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

 

posted @ 2017-08-08 07:22  安月冷  阅读(158)  评论(0编辑  收藏  举报