最短路
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; }
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; }
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; }
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; }
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; }
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; }
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; }
折花枝,恨花枝,准拟花开人共卮,开时人去时。
怕相思,已相思,轮到相思没处辞,眉间露一丝。