洛谷 P1396 营救
题目描述
“咚咚咚……”“查水表!”原来是查水表来了,现在哪里找这么热心上门的查表员啊!小明感动的热泪盈眶,开起了门……
妈妈下班回家,街坊邻居说小明被一群陌生人强行押上了警车!妈妈丰富的经验告诉她小明被带到了t区,而自己在s区。
该市有m条大道连接n个区,一条大道将两个区相连接,每个大道有一个拥挤度。小明的妈妈虽然很着急,但是不愿意拥挤的人潮冲乱了她优雅的步伐。所以请你帮她规划一条从s至t的路线,使得经过道路的拥挤度最大值最小。
输入输出格式
输入格式:
第一行四个数字n,m,s,t。
接下来m行,每行三个数字,分别表示两个区和拥挤度。
(有可能两个区之间有多条大道相连。)
输出格式:
输出题目要求的拥挤度。
输入输出样例
输入样例#1:
3 3 1 3 1 2 2 2 3 1 1 3 3
输出样例#1:
2
说明
数据范围
30% n<=10
60% n<=100
100% n<=10000,m<=2n,拥挤度<=10000
题目保证1<=s,t<=n且s<>t,保证可以从s区出发到t区。
样例解释:
小明的妈妈要从1号点去3号点,最优路线为1->2->3。
1.二分拥挤度+spfa验证
#include <ctype.h> #include <cstring> #include <cstdio> #include <queue> #define N 20005 using namespace std; inline void read(int &x) { register char ch=getchar(); for(x=0;!isdigit(ch);ch=getchar()); for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; } struct Edge { int to,val; Edge * next; }edge[N<<1],*head[N]; bool vis[N]; int sumedge,cnt[N],n,m,s,t,dis[N]; inline void ins(int u,int v,int w) { edge[++sumedge].next=head[u]; edge[sumedge].to=v; edge[sumedge].val=w; head[u]=edge+sumedge; } bool check(int Limit) { queue<int>q; q.push(s); for(int i=1;i<=n;i++) vis[i]=0,cnt[i]=0,dis[i]=0x3f3f3f3f; dis[s]=0; cnt[s]=1; vis[s]=1; for(int now=q.front();!q.empty();q.pop(),now=q.front()) { vis[now]=0; if(cnt[now]>=n) return 0; for(Edge * u=head[now];u;u=u->next) { int v=u->to; if(u->val<=Limit&&dis[v]>dis[now]+u->val) { dis[v]=dis[now]+u->val; if(!vis[v]) { vis[v]=1; q.push(v); cnt[v]++; } } } } return dis[t]!=0x3f3f3f3f; } int main() { read(n);read(m);read(s);read(t); for(int x,y,z;m--;) { read(x);read(y);read(z); ins(x,y,z); ins(y,x,z); } int ans; for(int l=0,r=0x3f3f3f3f,mid;l<=r;) { mid=l+r>>1; if(check(mid)) r=mid-1,ans=mid; else l=mid+1; } printf("%d\n",ans); return 0; }
2 spfa
#include <ctype.h> #include <cstring> #include <cstdio> #include <queue> #define N 20005 using namespace std; inline void read(int &x) { register char ch=getchar(); for(x=0;!isdigit(ch);ch=getchar()); for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; } struct Edge { int to,val; Edge * next; }edge[N<<1],*head[N]; bool vis[N]; int sumedge,cnt[N],n,m,s,t,dis[N]; inline void ins(int u,int v,int w) { edge[++sumedge].next=head[u]; edge[sumedge].to=v; edge[sumedge].val=w; head[u]=edge+sumedge; } void spfa() { queue<int>q; q.push(s); for(int i=1;i<=n;i++) vis[i]=0,dis[i]=0x3f3f3f3f; dis[s]=0; vis[s]=1; for(int now=q.front();!q.empty();q.pop(),now=q.front()) { vis[now]=0; for(Edge * u=head[now];u;u=u->next) { int v=u->to; if(dis[v]>max(u->val,dis[now])) { dis[v]=max(u->val,dis[now]); if(!vis[v]) { vis[v]=1; q.push(v); } } } } } int main() { read(n);read(m);read(s);read(t); for(int x,y,z;m--;) { read(x);read(y);read(z); ins(x,y,z); ins(y,x,z); } spfa(); printf("%d\n",dis[t]); return 0; }
3 最小生成树 代码来自zsq
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define N 100100 using namespace std; int x,y,z,n,m,s,t,ans,fa[N]; struct Edge { int x,y,z; }edge[N]; int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } int cmp(Edge a,Edge b) { return a.z<b.z; } int find(int x) { if(x==fa[x]) return x; fa[x]=find(fa[x]); return fa[x]; } int main() { n=read(),m=read(),s=read(),t=read(); for(int i=1;i<=m;i++) { x=read(),y=read(),z=read(); edge[i].x=x; edge[i].y=y; edge[i].z=z; } for(int i=1;i<=n;i++) fa[i]=i; sort(edge+1,edge+1+m,cmp); for(int num=0,i=1;i<=m;i++) { x=edge[i].x,y=edge[i].y; int fx=find(x),fy=find(y); if(fx==fy) continue; fa[fx]=fy; num++; ans=max(ans,edge[i].z); if(num==n-1||find(s)==find(t)) break; } printf("%d",ans); return 0; }
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。