https://www.luogu.com.cn/problem/P3906
P3906 Geodetic集合
bfs深搜的灵活应用,算我的薄弱点。
#include <bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,pre[50][50],dist[50],mp[50][50],k,num[50];
bool vis[50];
void bfs(int s,int t)
{
memset(num,0,sizeof(num)); //记录前驱结点个数
memset(dist,inf,sizeof(dist)); //dist数组都初始化为极大值,吴话可说
dist[s]=0; //起始结点距离为0
queue<int>q;q.push(s);
while(!q.empty())
{
s=q.front();q.pop();
for(int i=1;i<=n;i++)
{
if(mp[s][i]) //若存在边
{
if(dist[i]>dist[s]+1) //简单dp思想
{
dist[i]=dist[s]+1;
pre[i][++num[i]]=s; //以i为节点的前驱节点都标记为s(上一个结点),num[i]表示几个
q.push(i);
}
else if(dist[i]==dist[s]+1)
pre[i][++num[i]]=s;
}
}
}
memset(vis,0,sizeof(vis));q.push(t);vis[t]=1; //从目标结点t倒着搜上去
while(!q.empty())
{
s=q.front();q.pop();
for(int i=num[s];i>=1;i--) //以s为结点的前驱节点,标记为1
{
if(!vis[pre[s][i]])
vis[pre[s][i]]=1;
q.push(pre[s][i]);
}
}
for(int i=1;i<=n;i++)
{
if(vis[i])
printf("%d ",i);
}
cout<<endl;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y;scanf("%d%d",&x,&y);
mp[x][y]=1;mp[y][x]=1;
}
scanf("%d",&k);
for(int i=1;i<=k;i++)
{
int u,v;scanf("%d%d",&u,&v);
bfs(u,v);
}
return 0;
}
P3905 道路重建
https://www.luogu.com.cn/problem/P3905
只对被破坏的交通赋值,完好的交通赋值为0,求从a到b的最短路径即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn=200005;
const int inf=0x3f3f3f3f;
struct egde
{
int to,dis,nxt;
}e[maxn];
int n,m,d,a,b,s,head[maxn],dist[maxn],cnt,ag[5005][5005];
bool vis[maxn];
void add_edge(int from,int to,int dis)
{
e[++cnt].to=to;
e[cnt].dis=dis;
e[cnt].nxt=head[from];
head[from]=cnt;
}
struct node
{
int pos,dis;
bool operator <(const node &x)const
{
return x.dis<dis;
}
};
void dijkstra()
{
s=a;
dist[s]=0;
priority_queue<node>q;q.push(node{s,0});
while(!q.empty())
{
node cur=q.top();q.pop();
int now=cur.pos;
if(vis[now]) continue;
vis[now]=1;
for(int i=head[now];i!=-1;i=e[i].nxt)
{
int j=e[i].to;
if(dist[j]>dist[now]+e[i].dis)
{
dist[j]=dist[now]+e[i].dis;
q.push(node{j,dist[j]});
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
head[0]=-1;
for(int i=1;i<=n;i++)
head[i]=-1,dist[i]=inf;
for(int i=1;i<=m;i++)
{
int u,v,w;scanf("%d%d%d",&u,&v,&w);
ag[u][v]=w,ag[v][u]=w;
add_edge(u,v,0),add_edge(v,u,0);
}
scanf("%d",&d);
for(int g=1;g<=d;g++)
{
int x,y;scanf("%d%d",&x,&y);
for(int i=head[x];i!=-1;i=e[i].nxt)
{
if(e[i].to==y) e[i].dis=ag[x][y];
}
for(int i=head[y];i!=-1;i=e[i].nxt)
{
if(e[i].to==x) e[i].dis=ag[y][x];
}
}
scanf("%d%d",&a,&b);
dijkstra();
printf("%d\n",dist[b]);
return 0;
}
https://www.luogu.com.cn/problem/P6175
Floyd算法:复杂度高,但能算出任意两点的最短路径。
(此段注解使用别人的解释,非常有道理,对于处理最小环的问题)
我们知道,
在Floyd算法枚举 k的时候,已经得到了前 k-1 个点的最短路径,这 k-1 个点不包括点 k,并且他们的最短路径中也不包括 k 点。
那么我们便可以从这前 k-1 个点中选出两个点 i , j 来
因为 / i-j / 已经是 ( i , j ) 间的最短路径,且这个路径不包含 k 点
注解:这里 / i-j / 这样表达只是为了直观,实际中 ( i , j ) 间的最短路很可能不仅仅只有 / i-j / ,还有可能会有其他点,但是这条路径一定是 ( i , j ) 间的最短路
所以连接 / i-j-k-i / ,我们就得到了一个经过 i , j , k 的最小环
最后每次更新 ans 的最小值即可。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn=200;
int n,m;
int dis[maxn][maxn];
int mp[maxn][maxn];
signed main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j)dis[i][j]=mp[i][j]=inf;
for(int i=1;i<=m;i++)
{
int u,v,w;scanf("%d%d%d",&u,&v,&w);
dis[u][v]=min(dis[u][v],w);
dis[v][u]=min(dis[v][u],w);
mp[u][v]=min(mp[u][v],w);
mp[v][u]=min(mp[v][u],w);
}
int ans = inf;
for(int k=1;k<=n;k++)
{
for(int i=1;i<k;i++)
for(int j=i+1;j<k;j++)
ans = min(ans,dis[i][j]+mp[i][k]+mp[k][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]);
dis[j][i] = dis[i][j];
}
}
if(ans==inf)
cout<<"No solution."<<endl;
else
cout<<ans<<endl;
return 0;
}