ACM作业

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;

    
        
    
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值