B3647 【模板】Floyd
比较正常的dijkstra算法,即从起始点开始找最近的一点,然后松弛更新操作,最后找到最优解
#include<bits/stdc++.h>
using namespace std;
int main()
{ int dist[105][105];
int n,m;
cin>>n>>m;
int u,v,w;
int a[105][105],b[105][105];
int vis[105];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]=10001;
while(cin>>u>>v>>w&&m!=0)
{
a[u][v]=min(a[u][v],w);
a[v][u]=a[u][v];
m--;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{ if(i==j) a[i][j]=0;
}
int small,ans=0;
int minn,next;
int start;
minn=10001;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
dist[i][j]=a[i][j];
dist[j][i]=dist[i][j];
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{ if(j!=i){
start=i;
dist[i][i]=0;
int end=j;
memset(vis,0,sizeof(vis));
while(start!=end)
{small=10001;
for(int y=1;y<=n;y++)
{
if(a[start][y]!=minn&&y!=start)
{
dist[i][y]=min(dist[i][y],a[start][y]+dist[i][start]);
}
if(vis[y]!=1&&dist[i][y]<small&&y!=start)
{
next=y;
small=dist[i][y];
}
}
start=next;
if(small==10001) break;
vis[start]=1;
}
b[i][j]=dist[i][j];
}}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
b[i][j]=b[j][i];
if(i==j) b[i][j]=0;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
cout<<b[i][j]<<" ";
if(j==n) cout<<endl;
}
return 0;
}
P4779 【模板】单源最短路径(标准版)
dijkstra算法的升级版,由于n,m大小的限制,必须要有更优化的解才能做出来,考虑使用堆优化。
默认为大根堆,使用优先队列priority_queue且使用pair,和正常队列不同的是在于.top()是取出优先级最高的一个数。
对于不加规定的优先队列而言,.top()是选出最大的一个(大根堆,就是把最大的数放在顶部,每次取出顶部的数)
其次,使用了一个链式前向星存图的方法,解决了无法存过多数据的数组,这里其中有待理解。
可以理解为,每次输入的值都加以储存,用head(x)储存cnt,表明了起点为x且第cnt组输入的数据,可以帮助我们找到后面储存的y(x到y,y是重点),至于z而言,不同题目有不同要求,这里有权值,所以再用edge(x)储存下来其权值。
接着,对于运算符的重载,实际上是不需要的,由于我们想找到最小值,只需要make_pair(-dis(x),x) ,将输入的pair换成负数,自然就是最小的上来了。
for循环的问题,我们采取for(int i=head[x];i;i=nxt[i])的方式,每次取nxt(i),nxt(i)记录了head(x),就是意味着,上一次输入x的数据是第几组(cnt),找到他,然后开始进行dijkstra算法的松弛操作,如果松弛成功了,就make_pair(-dis(y),y),然后下一次循环时从y开始找,直到全部轮完,找到最小值
#include<bits/stdc++.h>
using namespace std;
int cnt=0;
int ver[2000005],edge[2000005],head[2000005],nxt[2000005],dis[10000000],vis[10000000];
void add(int x,int y,int z)
{
cnt++;
ver[cnt]=y;
edge[cnt]=z;
if(head[x]!=0) nxt[cnt]=head[x];
head[x]=cnt;
}
priority_queue<pair<int, int> > q;
int main()
{
int n,m,s;
cin>>n>>m>>s;
for(int i=1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
}
for(int i=1;i<=m;i++)
{
dis[i]=1000000000;
}
dis[1]=0;
memset(vis,0,sizeof(vis));
q.push(make_pair(0,1));
while(!q.empty())
{
int x=q.top().second;
q.pop();
for(int i=head[x];i;i=nxt[i])
{ int y=ver[i],z=edge[i];
if(dis[y]>dis[x]+z){
dis[y]=dis[x]+z;
q.push(make_pair(-dis[y],y));
}
}
}
for(int i=1;i<=n;i++)
cout<<dis[i]<<" ";
}
P2661 [NOIP2015 提高组] 信息传递
本题是一个并查集,即找出最小环,因此此时不能缩短路径,而是需要关注每一次的find,使用&cnt来传参
#include<bits/stdc++.h>
using namespace std;
int n,ans[1000000];
int minn=1000000;
int a[200005],b[200005];
int sum[200005],vis[200005];
int find(int x,int &cnt)
{ cnt++;
if(x==b[x]) return x;
else {
return find(b[x],cnt);;
}
}
int main()
{
int ans=100000000;
cin>>n;
for(int i=1;i<=n;i++)
b[i]=i;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
int cnt=0;
if(find(a[i],cnt)==i)
ans=min(ans,cnt);
else
b[i]=a[i];
}
cout<<ans;
}
P1144 最短路计数
也是一个dijkstra算法的堆优化,不同的是加入一个ans(x),如果正好相等的话,就是ans(y)+=ans(x),否则就将ans(y)传递给ans(x)。
#include<bits/stdc++.h>
using namespace std;
int cnt=0;
int ver[2000005],edge[2000005],head[2000005],nxt[2000005],dis[10000000],vis[10000000],ans[10000000];
void add(int x,int y)
{
cnt++;
ver[cnt]=y;
if(head[x]!=0) nxt[cnt]=head[x];
head[x]=cnt;
}
priority_queue<pair<int, int> > q;
int main()
{ int cnt=0;
int n,m;
cin>>n>>m;
memset(ans,0,sizeof(ans));
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
add(u,v);
}
for(int i=1;i<=m;i++)
{
dis[i]=1000000000;
}
dis[1]=0;ans[1]=1;
memset(vis,0,sizeof(vis));
q.push(make_pair(0,1));
while(!q.empty())
{
int x=q.top().second;
q.pop();
if(vis[x]==1) continue;
vis[x]=1;
for(int i=head[x];i;i=nxt[i])
{ int y=ver[i];
if(dis[y]>dis[x]+1){
dis[y]=dis[x]+1;
ans[y]=ans[x];
q.push(make_pair(-dis[y],y));
}
else if(dis[y]==dis[x]+1)
{
ans[y]+=ans[x];
ans[y]=ans[y]%100003;
}
}
}
for(int i=1;i<=n;i++)
cout<<ans[i]%100003<<endl;
}