【算法提高——第三讲(一)】图论

来自:算法提高课

第三章 图论

3.1 单源最短路的建图方式

3.1.1 1129. 热浪

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2510,M=6210,INF=1e9;
int n,m,s,ed;
int h[N],e[2*M],w[2*M],ne[2*M],idx;
int dis[N];
bool st[N];
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int spfa(int s)
{
    fill(dis,dis+N,INF);
    dis[s]=0;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        st[t]=false;

        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j]>dis[t]+w[i])
            {
                dis[j]=dis[t]+w[i];
                if(!st[j])
                {
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    return dis[ed];
}
int main()
{
    ios::sync_with_stdio(0);
    cin>>n>>m>>s>>ed;
    fill(h,h+N,-1);
    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c),add(b,a,c);
    }
    cout<<spfa(s);
    return 0;
}

3.1.2 1128. 信使

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=110,M=410,INF=1e9;
int n,m;
int h[N],e[M],w[M],ne[M],idx;
int dis[N];
bool st[N];

void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

void spfa(int s)
{
    fill(dis,dis+N,INF);
    dis[s]=0;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        st[t]=false;

        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j]>dis[t]+w[i])
            {
                dis[j]=dis[t]+w[i];
                if(!st[j])
                {
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
}
int main()
{
    fill(h,h+N,-1);
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c),add(b,a,c);
    }
    spfa(1);
    int _max=-INF;
    for(int i=1;i<=n;i++)
    {
        if(dis[i]==INF)
        {
            cout<<-1<<endl;
            return 0;
        }
        if(_max<dis[i])
        {
            _max=dis[i];
        }
    }
    cout<<_max<<endl;
    return 0;
}

3.1.3 1127. 香甜的黄油

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=810,M=2910,INF=1e9;
int n,p,C;
int h[N],e[M],w[M],ne[M],idx;
int dis[N];
bool st[N];
int cows[N];

void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

void spfa(int s)
{
    fill(dis,dis+N,INF);
    dis[s]=0;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        st[t]=false;

        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j]>dis[t]+w[i])
            {
                dis[j]=dis[t]+w[i];
                if(!st[j])
                {
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
}
int main()
{
    fill(h,h+N,-1);
    cin>>n>>p>>C;
    for(int i=0;i<n;i++)
    {
        cin>>cows[i];
    }
    for(int i=0;i<C;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c),add(b,a,c);
    }
    int ans=INF;
    for(int i=1;i<=p;i++)
    {
        spfa(i);
        int sum=0;
        for(int j=0;j<n;j++)
        {
            if(dis[cows[j]]==INF)
            {
                sum=INF;
                break;
            }
            else
            {
                sum+=dis[cows[j]];
            }
        }
        ans=min(ans,sum);
    }
    cout<<ans<<endl;
    return 0;
}

3.1.4 1126. 最小花费

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=2010,M=200010,INF=1e9;
int n,m,A,B;
int h[N],e[M],ne[M],idx;
double w[M];
bool st[N];
double dis[N];

void add(int a,int b,double c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

double spfa(int s)
{
    dis[s]=1;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        st[t]=false;

        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j]<dis[t]*w[i])
            {
                dis[j]=dis[t]*w[i];
                if(!st[j])
                {
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    return dis[B];
}
int main()
{
    fill(h,h+N,-1);
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int a,b;
        double c;
        cin>>a>>b>>c;
        c=(100-c)/100;
        add(a,b,c),add(b,a,c);
    }
    cin>>A>>B;
    printf("%.8f",100/spfa(A));
    return 0;
}

3.1.5 920. 最优乘车

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=510,INF=1e9;
int m,n;
int g[N][N];
int dis[N];
int stop[N];

void bfs()
{
    fill(dis,dis+N,INF);
    queue<int> q;
    dis[1]=0;
    q.push(1);

    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        for(int i=1;i<=n;i++)
        {
            if(g[t][i]&&dis[i]>dis[t]+1)
            {
                dis[i]=dis[t]+1;
                q.push(i);
            }
        }
    }
}
int main()
{
    cin>>m>>n;
    getchar();
    string line;
    while(m--)
    {
        getline(cin,line);
        int cnt=0,p;
        stringstream ssin(line);
        while(ssin>>p) stop[cnt++]=p;
        for(int i=0;i<cnt;i++)
        {
            for(int j=i+1;j<cnt;j++)
            {
                g[stop[i]][stop[j]]=1;
            }
        }
    }
    bfs();
    if(dis[n]==INF) cout<<"NO";
    else cout<<dis[n]-1;
    return 0;
}

3.1.6 903. 昂贵的聘礼

在这里插入图片描述
在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=110,INF=1e9;
int m,n;
int g[N][N];
int d[N];
int w[N],L[N];
bool st[N];
vector<PII> node[N];
int spfa(int left,int right)
{
    fill(d,d+N,INF);
    d[0]=0;
    queue<int> q;
    for(int i=0;i<=n;i++)
    {
        q.push(i);
        st[i]=true;
    }
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        st[t]=false;

        for(int i=0;i<=n;i++)
        {
            if(g[t][i]!=INF)
            {
                if(L[i]>=left&&L[i]<=right&&d[i]>d[t]+g[t][i])
                {
                    d[i]=d[t]+g[t][i];
                    if(!st[i])
                    {
                        q.push(i);
                        st[i]=true;
                    }
                }
            }
        }
    }
    return d[1];
}
int main()
{
    fill(g[0],g[0]+N*N,INF);
    cin>>m>>n;
    for(int i=1;i<=n;i++)
    {
        int p,l,x;
        cin>>p>>l>>x;
        w[i]=p;
        L[i]=l;
        for(int j=0;j<x;j++)
        {
            int t,v;
            cin>>t>>v;
            node[i].push_back(make_pair(t,v));
        }
    }
    for(int i=1;i<=n;i++)
    {
        g[i][i]=0;
        for(int j=0;j<node[i].size();j++)
        {
            int t=node[i][j].first,v=node[i][j].second;
            if(abs(L[i]-L[t])<=m)
            {
                g[t][i]=min(g[t][i],v);
            }
        }
    }
    for(int i=1;i<=n;i++) g[0][i]=w[i];
    int ans=INF;
    for(int i=L[1]-m;i<=L[1];i++)
    {
        ans=min(ans,spfa(i,i+m));
    }

    cout<<ans;
    return 0;
}

3.2 单源最短路的综合应用

3.2.1 1135. 新年好

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=50010,M=200010,INF=1e9;
int n,m;
int h[N],e[M],w[M],ne[M],idx;
bool st[N];
int dis[6][N];
int source[6];
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

void djk(int s,int dis[])
{
    fill(dis,dis+N,INF);
    fill(st,st+N,false);
    dis[s]=0;
    priority_queue<PII,vector<PII>,greater<PII> >heap;
    heap.push(make_pair(0,s));
    while(heap.size())
    {
        PII t=heap.top();
        heap.pop();
        int ver=t.second,distance=t.first;
        if(st[ver]) continue;
        for(int i=h[ver];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j]>dis[ver]+w[i])
            {
                dis[j]=dis[ver]+w[i];
                heap.push(make_pair(dis[j],j));
            }
        }
    }
}

int dfs(int u,int start,int distance)
{
    if(u>5) return distance;

    int res=INF;
    for(int i=1;i<=5;i++)
    {
        if(!st[i])
        {
            int next=source[i];
            st[i]=true;
            res=min(res,dfs(u+1,i,distance+dis[start][next]));
            st[i]=false;
        }
    }
    return res;
}
int main()
{
    fill(h,h+N,-1);
    cin>>n>>m;
    for(int i=1;i<=5;i++) cin>>source[i];
    source[0]=1;

    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c),add(b,a,c);
    }
    fill(st,st+N,false);
    for(int i=0;i<6;i++) djk(source[i],dis[i]);
    cout<<dfs(1,0,0);
    return 0;
}

3.2.2 340. 通信线路

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=20010,INF=1e9;
int n,m,K;
int h[N],e[M],w[M],ne[M],idx;
int dis[N];
bool st[N];
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool check(int bound)
{
    fill(dis,dis+N,INF);
    fill(st,st+N,false);
    dis[1]=0;
    deque<int> q;
    q.push_back(1);
    while(!q.empty())
    {
        int t=q.front();
        q.pop_front();
        if(st[t])
            continue;
        st[t]=true;
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i],v=w[i]>bound;
            if(dis[j]>dis[t]+v)
            {
                dis[j]=dis[t]+v;
                if(!v)
                {
                    q.push_front(j);
                }
                else
                {
                    q.push_back(j);
                }
            }
        }
    }
    return dis[n]<=K;
}
int main()
{
    fill(h,h+N,-1);
    cin>>n>>m>>K;
    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c),add(b,a,c);
    }
    int l=0,r=1e6+1;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    if(r==1e6+1) r=-1;
    cout<<r<<endl;
    return 0;
}

3.2.3 342. 道路与航线

在这里插入图片描述
代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=25010,M=1500010,INF=1e9;
int h[N],e[M],w[M],ne[M],idx;
int n,r,p,s;
int dis[N];
bool st[N];
int id[N];
vector<int> block[N];   //连通块编号
int bcnt;   //连通块个数
queue<int> q;   //拓扑排序队列
int din[N];
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int bid)
{
    id[u]=bid;
    block[bid].push_back(u);
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!id[j]) dfs(j,bid);
    }
}
void djk(int bid)
{
    priority_queue<PII,vector<PII>,greater<PII> > heap;
    for(int i=0;i<block[bid].size();i++)
    {
        int ver=block[bid][i];
        heap.push(make_pair(dis[ver],ver));
    }
    while(heap.size())
    {
        PII t=heap.top();
        heap.pop();

        int ver=t.second,distance=t.first;
        if(st[ver]) continue;
        st[ver]=true;

        for(int i=h[ver];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j]>dis[ver]+w[i])
            {
                dis[j]=dis[ver]+w[i];
                if(id[j]==id[ver]) heap.push(make_pair(dis[j],j));
            }
            if(id[j]!=id[ver]&&--din[id[j]]==0) q.push(id[j]);
        }
    }
}
void topsort()
{
    fill(dis,dis+N,INF);
    dis[s]=0;

    for(int i=1;i<=bcnt;i++)
    {
        if(!din[i])
        {
            q.push(i);
        }
    }
    while(q.size())
    {
        int t=q.front();
        q.pop();
        djk(t);
    }
}
int main()
{
    ios::sync_with_stdio(0);
    fill(h,h+N,-1);
    cin>>n>>r>>p>>s;
    for(int i=0;i<r;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c),add(b,a,c);
    }
    for(int i=1;i<=n;i++)
    {
        if(!id[i])
        {
            bcnt++;
            dfs(i,bcnt);
        }
    }

    for(int i=0;i<p;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        din[id[b]]++;
        add(a,b,c);
    }

    topsort();

    for(int i=1;i<=n;i++)
    {
        if(dis[i]>=INF/2) cout<<"NO PATH"<<endl;
        else cout<<dis[i]<<endl;
    }
    return 0;
}

3.2.4 341. 最优贸易

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=100010,M=2000010,INF=1e9;

int n,m;
int w[N];
int hs[N],ht[N],e[M],ne[M],idx;
int dmin[N],dmax[N];
int q[N];
bool st[N];

void add(int h[],int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void spfa(int h[],int dis[],int type)
{
    queue<int> q;
    if(type==0)
    {
        fill(dis,dis+N,INF);
        dis[1]=w[1];
        q.push(1);
    }
    else
    {
        fill(dis,dis+N,-INF);
        dis[n]=w[n];
        q.push(n);
    }

    while(q.size())
    {
        int t=q.front();
        q.pop();
        st[t]=false;
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(type==0&&dis[j]>min(dis[t],w[j])||type==1&&dis[j]<max(dis[t],w[j]))
            {
                if(type==0)
                {
                    dis[j]=min(dis[t],w[j]);
                }
                else
                {
                    dis[j]=max(dis[t],w[j]);
                }
                if(!st[j])
                {
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
}
int main()
{
    cin>>n>>m;
    fill(hs,hs+N,-1);
    fill(ht,ht+N,-1);

    for(int i=1;i<=n;i++) cin>>w[i];

    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(hs,a,b),add(ht,b,a);
        if(c==2) add(hs,b,a),add(ht,a,b);
    }
    spfa(hs,dmin,0);
    spfa(ht,dmax,1);
    int res=0;
    for(int i=1;i<=n;i++)
    {
        res=max(res,dmax[i]-dmin[i]);
    }
    cout<<res;
    return 0;
}

3.3 单源最短路的扩展应用

3.3.1 1137. 选择最佳线路

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=1010,M=40010,INF=1e9;
int n,m;
int ed;
int h[N],w[M],e[M],ne[M],idx;
int dis[N];
bool st[N];

void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

int djk(int s)
{
    fill(dis,dis+N,INF);
    fill(st,st+N,false);
    dis[s]=0;
    priority_queue<PII,vector<PII>,greater<PII> > heap;
    heap.push(make_pair(0,s));
    while(heap.size())
    {
        PII t=heap.top();
        heap.pop();
        int ver=t.second;
        if(st[ver]) continue;
        st[ver]=true;
        for(int i=h[ver];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j]>dis[ver]+w[i])
            {
                dis[j]=dis[ver]+w[i];
                heap.push(make_pair(dis[j],j));
            }
        }
    }
    return dis[ed];
}
int main()
{
    while(cin>>n>>m>>ed)
    {
        fill(h,h+N,-1);
        for(int i=0;i<m;i++)
        {
            int a,b,c;
            cin>>a>>b>>c;
            add(b,a,c);
        }
        djk(ed);
        int num,start;
        cin>>num;
        int ans=INF;
        for(int i=0;i<num;i++)
        {
            cin>>start;
            ans=min(ans,dis[start]);
        }
        if(ans!=INF) cout<<ans<<endl;
        else cout<<-1<<endl;
    }
    return 0;
}

3.3.2 1131. 拯救大兵瑞恩

在这里插入图片描述

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=11,M=400,P=1<<10,INF=1e9;

int n,m,p,k;
int h[N*N],e[M],w[M],ne[M],idx;
int g[N][N],key[N*N];
int dis[N*N][P];
bool st[N*N][P];

set<PII> edges;

void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

void build()
{
    int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            for(int u=0;u<4;u++)
            {
                int x=i+dx[u],y=j+dy[u];
                if(!x||x>n||!y||y>m) continue;
                int a=g[i][j],b=g[x][y];
                if(!edges.count(make_pair(a,b))) add(a,b,0);
            }
        }
    }
}

int bfs()
{
    //memset(dis,0x3f,sizeof dis);
    fill(dis[0],dis[0]+N*N*P,INF);
    dis[1][0]=0;

    deque<PII> q;
    q.push_back(make_pair(1,0));

    while(q.size())
    {
        PII t=q.front();
        q.pop_front();

        if(st[t.first][t.second]) continue;
        st[t.first][t.second]=true;

        if(t.first==n*m) return dis[t.first][t.second];

        if(key[t.first])
        {
            int state=t.second|key[t.first];
            if(dis[t.first][state]>dis[t.first][t.second])
            {
                dis[t.first][state]=dis[t.first][t.second];
                q.push_front(make_pair(t.first,state));
            }
        }

        for(int i=h[t.first];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(w[i]&&!(t.second>>w[i]-1&1)) continue;
            if(dis[j][t.second]>dis[t.first][t.second]+1)
            {
                dis[j][t.second]=dis[t.first][t.second]+1;
                q.push_back(make_pair(j,t.second));
            }
        }
    }
    return -1;
}
int main()
{
    cin>>n>>m>>p>>k;

    for(int i=1,t=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            g[i][j]=t++;
        }
    }

    fill(h,h+N*N,-1);
    for(int i=0;i<k;i++)
    {
        int x1,y1,x2,y2,c;
        cin>>x1>>y1>>x2>>y2>>c;
        int a=g[x1][y1],b=g[x2][y2];
        edges.insert(make_pair(a,b)),edges.insert(make_pair(b,a));
        if(c) add(a,b,c),add(b,a,c);
    }

    build();

    int num;
    cin>>num;
    for(int i=0;i<num;i++)
    {
        int x,y,id;
        cin>>x>>y>>id;
        key[g[x][y]]|=1<<id-1;
    }

    cout<<bfs()<<endl;
    return 0;
}

3.3.3 1134. 最短路计数

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=100010,M=400010,mod=100003;

int n,m;
int h[N],e[M],ne[M],idx;
int dis[N],cnt[N];

void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void bfs()
{
    memset(dis,0x3f,sizeof dis);
    dis[1]=0,cnt[1]=1;

    queue<int> q;
    q.push(1);

    while(q.size())
    {
        int t=q.front();
        q.pop();

        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j]>dis[t]+1)
            {
                dis[j]=dis[t]+1;
                cnt[j]=cnt[t];
                q.push(j);
            }
            else if(dis[j]==dis[t]+1)
            {
                cnt[j]=(cnt[j]+cnt[t])%mod;
            }
        }
    }
}
int main()
{
    memset(h,-1,sizeof h);

    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        add(a,b),add(b,a);
    }

    bfs();

    for(int i=1;i<=n;i++)
    {
        cout<<cnt[i]<<endl;
    }
    return 0;
}

3.3.4 383. 观光


在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=10010;

struct Ver{
    int ver,type,dist;
    bool operator > (const Ver &w) const
    {
        return dist>w.dist;
    }
    Ver(int _ver,int _type,int _dist)
    {
        ver=_ver,type=_type,dist=_dist;
    }
};

int n,m;
int S,T;
int h[N],e[M],w[M],ne[M],idx;
int dis[N][2],cnt[N][2];

bool st[N][2];

void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

int djk()
{
    memset(st,0,sizeof st);
    memset(cnt,0,sizeof cnt);
    memset(dis,0x3f,sizeof dis);
    dis[S][0]=0,cnt[S][0]=1;

    priority_queue<Ver,vector<Ver>,greater<Ver> > heap;
    heap.push(Ver(S,0,0));

    while(heap.size())
    {
        Ver t=heap.top();
        heap.pop();

        int ver=t.ver,type=t.type,distance=t.dist,_count=cnt[ver][type];
        if(st[ver][type]) continue;
        st[ver][type]=true;

        for(int i=h[ver];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j][0]>distance+w[i])
            {
                dis[j][1]=dis[j][0],cnt[j][1]=cnt[j][0];
                heap.push(Ver(j,1,dis[j][1]));
                dis[j][0]=distance+w[i],cnt[j][0]=_count;
                heap.push(Ver(j,0,dis[j][0]));
            }
            else if(dis[j][0]==distance+w[i])
            {
                cnt[j][0]+=_count;
            }
            else if(dis[j][1]>distance+w[i])
            {
                dis[j][1]=distance+w[i],cnt[j][1]=_count;
                heap.push(Ver(j,1,dis[j][1]));
            }
            else if(dis[j][1]==distance+w[i])
            {
                cnt[j][1]+=_count;
            }
        }
    }
    int res=cnt[T][0];
    if(dis[T][0]+1==dis[T][1]) res+=cnt[T][1];

    return res;
}
int main()
{
    int cases;
    cin>>cases;
    while(cases--)
    {
        cin>>n>>m;
        memset(h,-1,sizeof h);
        idx=0;

        for(int i=0;i<m;i++)
        {
            int a,b,c;
            cin>>a>>b>>c;
            add(a,b,c);
        }
        cin>>S>>T;

        cout<<djk()<<endl;
    }
    return 0;
}

3.4 Floyd算法

3.4.1 1125. 牛的旅行

在这里插入图片描述
在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=160;
const double INF=1e20;

char g[N][N];
PII q[N];
int n;
double d[N][N],maxd[N];

double get_dist(PII a,PII b)
{
    double x=a.first-b.first,y=a.second-b.second;
    return sqrt(x*x+y*y);
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>q[i].first>>q[i].second;
    }
    for(int i=0;i<n;i++)
    {
        cin>>g[i];
    }

    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i!=j)
            {
                if(g[i][j]=='1') d[i][j]=get_dist(q[i],q[j]);
                else d[i][j]=INF;
            }
        }
    }

    for(int k=0;k<n;k++)
    {
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
            }
        }
    }

    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(d[i][j]<INF)
            {
                maxd[i]=max(maxd[i],d[i][j]);
            }
        }
    }

    double res1=0;
    for(int i=0;i<n;i++)
        res1=max(res1,maxd[i]);

    double res2=INF;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(d[i][j]>=INF)
            {
                double dist=get_dist(q[i],q[j]);
                res2=min(res2,maxd[i]+dist+maxd[j]);
            }
        }
    }

    printf("%.6f",max(res1,res2));
    return 0;
}

3.4.2 343. 排序

在这里插入图片描述
在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=30;

int n,m;
bool g[N][N],d[N][N];
bool st[N];

void floyd()
{
    memcpy(d,g,sizeof d);

    for(int k=0;k<n;k++)
    {
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                d[i][j]|=d[i][k]&&d[k][j];
            }
        }
    }
}

int check()
{
    for(int i=0;i<n;i++)
    {
        if(d[i][i])
            return 2;
    }

    for(int i=0;i<n;i++)
    {
        for(int j=0;j<i;j++)
        {
            if(!d[i][j]&&!d[j][i])
            {
                return 0;
            }
        }
    }
    return 1;
}

char get_min()
{
    for(int i=0;i<n;i++)
    {
        if(!st[i])
        {
            bool flag=true;
            for(int j=0;j<n;j++)
            {
                if(!st[j]&&d[j][i])
                {
                    flag=false;
                    break;
                }
            }
            if(flag)
            {
                st[i]=true;
                return i+'A';
            }
        }
    }
}
int main()
{
    while(true)
    {
        cin>>n>>m;
        if(n==0&&m==0)
            break;

        memset(g,0,sizeof g);
        //注意type的意义和讲的时候不一样
        int type=0,t;
        for(int i=1;i<=m;i++)
        {
            string str;
            cin>>str;
            int a=str[0]-'A',b=str[2]-'A';

            if(!type)
            {
                g[a][b]=1;
                floyd();
                type=check();
                if(type) t=i;
            }
        }

        if(!type)
            cout<<"Sorted sequence cannot be determined."<<endl;
        else if(type==2)
            cout<<"Inconsistency found after "<<t<<" relations."<<endl;
        else
        {
            memset(st,0,sizeof st);
            cout<<"Sorted sequence determined after "<<t<<" relations: ";
            for(int i=0;i<n;i++)
                cout<<get_min();
            cout<<"."<<endl;
        }
    }
    return 0;
}

3.4.3 344. 观光之旅

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=110,INF=0x3f3f3f3f;

int n,m;
int d[N][N],g[N][N];
int pos[N][N];
int path[N],cnt;

void get_path(int i,int j)
{
    if(pos[i][j]==0) return;

    int k=pos[i][j];
    get_path(i,k);
    path[cnt++]=k;
    get_path(k,j);
}
int main()
{
    cin>>n>>m;

    memset(g,0x3f,sizeof g);
    for(int i=1;i<=n;i++) g[i][i]=0;

    while(m--)
    {
        int a,b,c;
        cin>>a>>b>>c;
        g[a][b]=g[b][a]=min(g[a][b],c);
    }

    int res=INF;
    memcpy(d,g,sizeof d);

    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<k;i++)
        {
            //for(int j=1;j<i;j++)
            for(int j=i+1;j<k;j++)
            {
                if((long long)d[i][j]+g[i][k]+g[k][j]<res)
                {
                    res=d[i][j]+g[i][k]+g[k][j];
                    cnt=0;
                    path[cnt++]=k;
                    path[cnt++]=i;
                    get_path(i,j);
                    path[cnt++]=j;
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(d[i][j]>d[i][k]+d[k][j])
                {
                    d[i][j]=d[i][k]+d[k][j];
                    pos[i][j]=k;
                }
            }
        }
    }
    if(res==INF) cout<<"No solution.";
    for(int i=0;i<cnt;i++)
    {
        cout<<path[i]<<" ";
    }
    return 0;
}

3.4.4 345. 牛站

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=210,M=2010,INF=0x3f3f3f3f;

int k,n,m,S,E;
int g[N][N];
int res[N][N];

void mul(int c[][N],int a[][N],int b[][N])
{
    static int temp[N][N];
    memset(temp,0x3f,sizeof temp);
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                temp[i][j]=min(temp[i][j],a[i][k]+b[k][j]);
            }
        }
    }
    memcpy(c,temp,sizeof temp);
}

void qmi()
{
    memset(res,0x3f,sizeof res);
    for(int i=1;i<=n;i++) res[i][i]=0;

    while(k)
    {
        if(k&1) mul(res,res,g);
        mul(g,g,g);
        k>>=1;
    }
}
int main()
{
    cin>>k>>m>>S>>E;
    memset(g,0x3f,sizeof g);
    map<int,int> mp;

    if(mp.count(S)==0) mp[S]=++n;
    if(mp.count(E)==0) mp[E]=++n;
    S=mp[S],E=mp[E];
    while(m--)
    {
        int a,b,c;
        cin>>c>>a>>b;
        if(mp.count(a)==0) mp[a]=++n;
        if(mp.count(b)==0) mp[b]=++n;
        a=mp[a],b=mp[b];

        g[a][b]=g[b][a]=min(g[a][b],c);
    }

    qmi();

    cout<<res[S][E]<<endl;
    return 0;
}

3.5 最小生成树

3.5.1 1140. 最短网络

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=110,INF=0x3f3f3f3f;
int n;
int g[N][N];
int dis[N];
bool st[N];

int prim()
{
    memset(dis,0x3f,sizeof dis);

    int res=0;
    for(int i=0;i<n;i++)
    {
        int t=-1;
        for(int j=1;j<=n;j++)
        {
            if(!st[j]&&(t==-1||dis[t]>dis[j]))
                t=j;
        }
        if(i&&dis[t]==INF)
            return INF;

        if(i) res+=dis[t];

        st[t]=true;

        for(int j=1;j<=n;j++)
            dis[j]=min(dis[j],g[t][j]);
    }
    return res;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            cin>>g[i][j];

    cout<<prim();
    return 0;
}

3.5.2 1141. 局域网

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=110,INF=0x3f3f3f3f;
int n,m,sum;
int p[N];

struct Edge{
    int a,b,w;
    bool operator < (const Edge &W)const
    {
        return w<W.w;
    }
}edges[N];

int findP(int x)
{
    if(p[x]!=x) p[x]=findP(p[x]);
    return p[x];
}
int kruskal()
{
    sort(edges,edges+m);
    for(int i=1;i<=n;i++) p[i]=i;

    int res=0;
    for(int i=0;i<m;i++)
    {
        int a=edges[i].a,b=edges[i].b,w=edges[i].w;

        a=findP(a),b=findP(b);
        if(a!=b)
        {
            p[a]=b;
            res+=w;
        }
    }
    return res;
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        edges[i].a=a,edges[i].b=b,edges[i].w=c;
        sum+=c;
    }
    cout<<sum-kruskal()<<endl;
    return 0;
}

3.5.3 1142. 繁忙的都市

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=310,M=80010;
int n,m;
int p[N];
struct Edge{
    int a,b,w;
}edges[M];
bool cmp(Edge a,Edge b)
{
    return a.w<b.w;
}

int findP(int x)
{
    if(p[x]!=x) return p[x]=findP(p[x]);
    return p[x];
}
int kruskal()
{
    sort(edges,edges+m,cmp);

    for(int i=1;i<=n;i++) p[i]=i;

    int res=-1;
    for(int i=0;i<m;i++)
    {
        int a=edges[i].a,b=edges[i].b,w=edges[i].w;

        a=findP(a),b=findP(b);
        if(a!=b)
        {
            p[a]=b;
            res=max(res,w);
        }
    }
    return res;
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<m;i++)
        cin>>edges[i].a>>edges[i].b>>edges[i].w;

    cout<<n-1<<" "<<kruskal()<<endl;


    return 0;
}

3.5.4 1143. 联络员

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2010,M=10010;

int n,m;
int p[N];
struct Edge{
    int a,b,w,type;
}edges[M];

bool cmp(Edge a,Edge b)
{
    if(a.type!=b.type)
        return a.type<b.type;
    else
        return a.w<b.w;
}

int findP(int x)
{
    if(p[x]!=x) return p[x]=findP(p[x]);
    return p[x];
}
int kruskal()
{
    sort(edges,edges+m,cmp);

    for(int i=1;i<=n;i++) p[i]=i;

    int res=0;
    for(int i=0;i<m;i++)
    {
        int type=edges[i].type,a=edges[i].a,b=edges[i].b,w=edges[i].w;

        a=findP(a),b=findP(b);
        if(a!=b)
        {
            p[a]=b;
            res+=w;
        }
        else if(type==1)
        {
            res+=w;
        }
    }
    return res;
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<m;i++)
        cin>>edges[i].type>>edges[i].a>>edges[i].b>>edges[i].w;
    cout<<kruskal();
    return 0;
}

3.5.5 1144. 连接格点

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=2000010;
int n,m;
int p[M];
int cnt;
int mp[M];
int dx[2]={0,1},dy[2]={1,0};
struct Edge{
    int a,b,w;
}edges[M];
bool cmp(Edge a,Edge b)
{
    return a.w<b.w;
}
int findP(int x)
{
    if(p[x]!=x) p[x]=findP(p[x]);
    return p[x];
}

int kruskal()
{
    sort(edges,edges+cnt,cmp);

    int res=0;
    for(int i=0;i<cnt;i++)
    {
        int a=edges[i].a,b=edges[i].b,w=edges[i].w;
        a=findP(a),b=findP(b);
        if(a!=b)
        {
            p[a]=b;
            res+=w;
        }
    }
    return res;
}
int main()
{
    cin>>n>>m;
    int x1,y1,x2,y2;
    for(int i=1;i<=N*N;i++) p[i]=i;
    while(cin>>x1>>y1>>x2>>y2)
    {
        int a=(x1-1)*n+y1,b=(x2-1)*n+y2;
        mp[a]=b;
        a=findP(a),b=findP(b);
        if(a!=b)
            p[a]=b;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            for(int k=0;k<2;k++)
            {
                int x=i+dx[k],y=j+dy[k];
                if(x<=0||x>n||y<=0||y>m)
                    continue;
                int a=(i-1)*n+j,b=(x-1)*n+y;
                if(mp[a]==b)
                    continue;
                edges[cnt].a=a,edges[cnt].b=b;
                if(i==x)
                    edges[cnt].w=2;
                else
                    edges[cnt].w=1;
                cnt++;

            }
        }
    }

    cout<<kruskal();
    return 0;
}

3.6 最小生成树的扩展应用

3.6.1 1146. 新的开始

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=310,M=100010;
int n,m;
int p[N];
int money[N];
struct Edge{
    int a,b,w;
}edges[M];
bool cmp(Edge a,Edge b)
{
    return a.w<b.w;
}

int findP(int x)
{
    if(p[x]!=x) return p[x]=findP(p[x]);
    return p[x];
}

int kruskal()
{
    sort(edges,edges+m,cmp);
    for(int i=1;i<=n+1;i++) p[i]=i;

    int res=0;
    for(int i=0;i<m;i++)
    {
        int a=edges[i].a,b=edges[i].b,w=edges[i].w;

        a=findP(a),b=findP(b);
        if(a!=b)
        {
            p[a]=b;
            res+=w;
        }
    }
    return res;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>money[i];

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            int w;
            cin>>w;
            if(i<j)
            {
                edges[m].a=i,edges[m].b=j,edges[m].w=w;
                m++;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        edges[m].a=n+1,edges[m].b=i,edges[m].w=money[i];
        m++;
    }

    cout<<kruskal();
    return 0;
}

3.6.2 1145. 北极通讯网络

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=510,M=250010;

int n,m,k;
int p[N];
PII mp[N];
struct Edge{
    int a,b;
    double w;
}edges[M];
bool cmp(Edge a,Edge b)
{
    return a.w<b.w;
}

int findP(int x)
{
    if(p[x]!=x) return p[x]=findP(p[x]);
    return p[x];
}

int check()
{
    set<int> st;
    for(int i=1;i<=n;i++)
    {
        st.insert(findP(i));
    }
    return st.size();
}
double kruskal()
{
    sort(edges,edges+m,cmp);

    for(int i=1;i<=n;i++) p[i]=i;

    double res=0;
    for(int i=0;i<m;i++)
    {
        int a=edges[i].a,b=edges[i].b;
        double w=edges[i].w;

        a=findP(a),b=findP(b);
        if(a!=b)
        {
            p[a]=b;
            res=w;
        }
        if(check()<=k)
            break;
    }
    return res;
}
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        int x,y;
        cin>>x>>y;
        mp[i]=make_pair(x,y);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            double x1=mp[i].first,y1=mp[i].second,x2=mp[j].first,y2=mp[j].second;
            double w=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
            edges[m].a=i,edges[m].b=j,edges[m].w=w;
            m++;
        }
    }

    printf("%.2f",kruskal());
    return 0;
}

3.6.3 346. 走廊泼水节

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=6010,M=6010;
int T,n,m;
int p[N],sz[N];
map<PII,int> mp;

struct Edge{
    int a,b,w;
}edges[M];

bool cmp(Edge a,Edge b)
{
    return a.w<b.w;
}

int findP(int x)
{
    if(p[x]!=x) return p[x]=findP(p[x]);
    return p[x];
}

int kruskal()
{
    sort(edges,edges+m,cmp);

    for(int i=1;i<=n;i++)
    {
        p[i]=i;
        sz[i]=1;
    }

    int res=0;
    for(int i=0;i<m;i++)
    {
        int a=edges[i].a,b=edges[i].b,w=edges[i].w;

        a=findP(a),b=findP(b);
        if(a!=b)
        {
            res+=(sz[a]*sz[b]-1)*(w+1);
            sz[b]+=sz[a];
            p[a]=b;

        }
    }
    return res;
}

int main()
{
    cin>>T;
    while(T--)
    {
        cin>>n;
        for(int i=0;i<n-1;i++)
        {
            int a,b,w;
            cin>>a>>b>>w;
            edges[i].a=a,edges[i].b=b,edges[i].w=w;
        }
        m=n-1;
        cout<<kruskal()<<endl;
    }
    return 0;
}

3.6.4 1148. 秘密的牛奶运输

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=510,M=10010;
const LL INF=1e18;

int n,m;
int p[N];
int dis1[N][N],dis2[N][N];
int h[N],e[N*2],w[N*2],ne[N*2],idx;

struct Edge{
    int a,b,w;
    bool type;
}edges[M];

bool cmp(Edge a,Edge b)
{
    return a.w<b.w;
}

void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

int findP(int x)
{
    if(p[x]!=x) return p[x]=findP(p[x]);
    return p[x];
}

void dfs(int u,int fa,int maxd1,int maxd2,int d1[],int d2[])
{
    d1[u]=maxd1,d2[u]=maxd2;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(j!=fa)
        {
            int td1=maxd1,td2=maxd2;
            if(w[i]>td1) td2=td1,td1=w[i];
            else if(w[i]<td1&&w[i]>td2) td2=w[i];
            dfs(j,u,td1,td2,d1,d2);
        }
    }
}
LL kruskal()
{
    sort(edges,edges+m,cmp);

    for(int i=1;i<=n;i++) p[i]=i;

    LL res=0;
    for(int i=0;i<m;i++)
    {
        int a=edges[i].a,b=edges[i].b,w=edges[i].w;

        int pa=findP(a),pb=findP(b);
        if(pa!=pb)
        {
            p[pa]=pb;
            add(a,b,w),add(b,a,w);
            edges[i].type=true;
            res+=w;
        }
    }
    return res;
}
int main()
{
    memset(h,-1,sizeof h);

    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        cin>>edges[i].a>>edges[i].b>>edges[i].w;
    }

    LL sum=kruskal();

    for(int i=1;i<=n;i++)
        dfs(i,-1,-1e9,-1e9,dis1[i],dis2[i]);

    LL res=INF;
    for(int i=0;i<m;i++)
    {
        if(!edges[i].type)
        {
            int a=edges[i].a,b=edges[i].b,w=edges[i].w;
            if(w>dis1[a][b])
            {
                res=min(res,sum+w-dis1[a][b]);
            }
            else if(w>dis2[a][b])
            {
                res=min(res,sum+w-dis2[a][b]);
            }
        }
    }
    cout<<res;
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值