• 18寒假第七测


    又回学校了,╮(╯▽╰)╭

    第一题:由于城市群之间的距离是相同的特性,根据网络流想到增点,用一个新点代表一个城市群,注意判断出边和入边,我是用二维dis表示出入+SPFA

    #include<cstdio>
    #include<cstdlib>
    #include<queue>
    #include<cstring>
    #include<iostream>
    using namespace std;
    #define INF 1000000008
    const int maxn = 4e5+5;
    struct edge{
        int to,co;
    };
    
    vector <edge> G[maxn];
    bool inq[maxn];
    int dis[maxn][2];
    void read(int &x){
        int f=1;x=0;char s=getchar();
        while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
        while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
        x*=f;
    }
    int n,m,m1,m2,s,t;
    void SPFA(int s){
        queue <int> Q;
        Q.push(s);
        dis[s][0] = 0;
        inq[s] = 1;
        
        while(!Q.empty()){
            int u = Q.front();
            Q.pop();
            inq[u] = 0;
            for(int i = 0; i < (int)G[u].size(); i++){
                edge &e = G[u][i];
                int x = 0,y = 0;
                if(u>n&&e.to>n)y=1;
                if(u>n&&e.to<=n)x=1;
                if(dis[e.to][y] > dis[u][x] + e.co){
                    dis[e.to][y] = dis[u][x] + e.co;
                    if(!inq[e.to])Q.push(e.to), inq[e.to] = 1;
                }    
    
                
            }
        }
    }
    int main(){
        freopen("map.in","r",stdin);
        freopen("map.out","w",stdout);
        
        read(n),read(m);
        int N = 1+n+m;
        for(int i = 1+n; i < N; i++){
            int u, k;
            read(k);
            while(k--){
                read(u);
                G[i].push_back((edge){u,0});
                G[u].push_back((edge){i,0});
            }
        }
        read(m1);
        while(m1--){
            int u,v,w;
            read(u),read(v),read(w);
            G[u].push_back((edge){v,w});
            G[v].push_back((edge){u,w});
        }
        read(m2);
        while(m2--){
            int u,v,w;
            read(u),read(v),read(w);
            G[u+n].push_back((edge){v+n,w});
            G[v+n].push_back((edge){u+n,w});
        }
        read(s),read(t);
        for(int i = 1; i <= N; i++)
            dis[i][0] = dis[i][1] = INF;
        SPFA(s);
        if(dis[t][0] == INF&& dis[t][1] == INF)cout<<-1<<endl;
        else cout<<min(dis[t][0], dis[t][1])<<endl;
            
    }

    标答是建一个出点和一个入点+dijstra

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <cstdlib>
    #include <map>
    #include <set>
    #include <vector>
    #include <queue>
    
    using namespace std;
    
    const int maxn = 60010;
    const int maxm = 320010;
    
    struct edge
    {
        int u,v,next,w;
    }e[maxm];
    int h[maxn],num;
    long long dis[maxn];
    int n,m,m1,m2;
    struct node
    {
        int a,b;
    };
    
    void build(int u,int v,int w)
    {
        num++;
        e[num].u = u;
        e[num].v = v;
        e[num].w = w;
        e[num].next = h[u];
        h[u] = num;
    }
    
    typedef pair<long long,int>P;
    priority_queue<P,vector<P>,greater<P> >q;
    long long inf;
    
    long long dij(int s,int t)
    {
        int u,v;
        memset(dis,60,sizeof(dis));
        inf  = dis[t];
        dis[s] = 0;
        q.push(P(0,s));
        while(!q.empty())
        {
            P p = q.top();
            u = p.second;
            q.pop();
            if(dis[u] < p.first)
                continue;
            for(int i = h[u]; i; i = e[i].next)
            {
                v = e[i].v;
                if(dis[v] > dis[u] + e[i].w)
                {
                    dis[v] = dis[u] + e[i].w;
                    q.push(P(dis[v],v));
                }
            }
        }
        return dis[t];
    }
    
    int main()
    {
        freopen("map.in","r",stdin);
        freopen("map.out","w",stdout);
        cin >> n >> m;
        for(int i = 1; i <= m; i++)
        {
            int k,u;
            scanf("%d",&k);
            while(k--)
            {
                scanf("%d",&u);
                build(n+i+m,u,0);
                build(u,n+i,0);
            }
        }
        cin >> m1;
        for(int i = 1; i <= m1; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            build(u,v,w);
            build(v,u,w);
        }
        cin >> m2;
        for(int i = 1; i <= m2; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            build(u+n,v+n+m,w);
            build(v+n,u+n+m,w);
        }
        int s,t;
        scanf("%d%d",&s,&t);
        long long ans = dij(s,t);
        if(ans == inf)
            printf("-1
    ");
        else
            printf("%lld
    ",ans);
        return 0;
    }

    第二题 解析见第一测最后一题,一定要注意tarjan里面弹栈

    #include<cstdio>
    #include<cstdlib>
    #include<queue>
    #include<cstring>
    #include<iostream>
    #include<vector>
    using namespace std;
    const int maxn = 30005;
    void read(int &x){
        int f=1;x=0;char s=getchar();
        while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
        while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
        x*=f;
    }
    
    int dfn[maxn],low[maxn],idx,scc[maxn],scccnt;
    int t[maxn],top,r[maxn];
    bool ins[maxn];
    vector <int> G[maxn], g[maxn];
    void tarjan(int s){
        dfn[s] = low[s] = ++idx;
        t[++top] = s; ins[s] = 1;
        for(int i = 0; i < (int)G[s].size(); i++){
            int v = G[s][i];
            if(!dfn[v]){
                tarjan(v);
                low[s] = min (low[s], low[v]);
            }
            else if(ins[v])low[s] = min(low[s], dfn[v]);
        }
        
        if(low[s] == dfn[s]){
            scccnt++;
            int x = low[s];
            while(1){
                scc[t[top]] = scccnt;
                ins[t[top--]] = 0;
                if(t[top+1] == s)break;
            }
        }
    } 
    bool topsort(){
        queue <int> q;
        int cnt = 0;
        for(int i = 1; i <= scccnt; i++)
            if(!r[i])cnt++, q.push(i);
        if(cnt >= 2)return 0;
        while(!q.empty()){
            cnt = 0;
            int i = q.front();
            q.pop();
            for(int j = 0; j < g[i].size(); j++){
                int v = g[i][j];
                r[v]--;
                if(!r[v]){
                    q.push(v);
                    cnt++;
                }
            }
            if(cnt >= 2)return 0;
        }
            
        return 1;
    }
    int main(){
        freopen("graph.in","r",stdin);
        freopen("graph.out","w",stdout);
        int T,n,m;
        read(T);
        while(T--){
            read(n),read(m);
            
            scccnt = idx = top = 0;
            memset(r,0,sizeof(r));
            memset(dfn,0,sizeof(dfn));
            memset(low,0,sizeof(low));
            memset(ins,0,sizeof(ins));
            memset(scc,0,sizeof(scc));
            for(int i = 1; i <= n; i++)
                G[i].clear(),g[i].clear();
                    
            for(int i = 1; i <= m; i++){
                int u, v;
                read(u),read(v);
                G[u].push_back(v);
            }
            for(int i = 1; i <= n; i++)
                if(!dfn[i])tarjan(i);
            for(int i = 1; i <= n; i++){
                int u = scc[i];
                for(int j = 0; j < (int)G[i].size(); j++){
                    int v = scc[G[i][j]];
                    if(u != v){
                        g[u].push_back(v);
                        r[v]++;
                    }
                }
            }
            if(topsort())printf("Yes
    ");
            else printf("No
    ");
        }
        
    }

    第三题 先一个裸地最小生成树,在对选择每个公司进行模拟(在新图上连边),还需要新连的边一定在原生成树的边中,正确性易见,这样复杂度从m*k变成了m*n;

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstdlib>
    #include<vector>
    using namespace std;
    #define INF 50000000000009LL 
    const int maxn = 30005;
    const int maxm = 200000+5;
    int f[maxn], a[maxn];
    struct edge { 
        int u,v,co;
     };
    edge G[maxm],N[maxm];
    vector <int> K[maxn];
    void read(int &x){
        int f=1;x=0;char s=getchar();
        while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
        while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
        x*=f;
    }
    int Find(int x){
        return f[x] == x ? x : f[x] = Find(f[x]);
    }
    void Union(int u,int v){
        int x = Find(u), y =Find(v);
        f[x]= y;
    }
    bool check(int u,int v){
        return Find(u) == Find(v);
    }
    bool cmp(edge a, edge b){
        return a.co < b.co;
    }
    int main(){
        freopen("airplane.in","r",stdin);
        freopen("airplane.out","w",stdout);
        int n, m, k, tot = 0, cnt = 0;
        long long ans = INF;
        int q = 0;
        read(n),read(m),read(k);
        for(int i = 1; i <= m ;i++)read(a[i]);
        for(int i = 1; i <= k; i++){
            int u, v, w, s;
            read(u),read(v),read(w),read(s);
            G[++tot]=(edge){u,v,w};
            G[++tot]=(edge){v,u,w};
            K[s].push_back(u);
            K[s].push_back(v);
        }
        
        sort(G+1, G+1+tot, cmp);
        for(int i = 1; i <= n; i++)f[i] = i;    
        for(int i = 1; i <= tot; i++){
            int u = G[i].u, v = G[i].v;
            if(!check(u, v)){
                Union(u, v);
                N[++q] = G[i];
            }
            if(q == n-1)break;
        }
        
        sort(N+1, N+1+q, cmp);
        for(int i = 1; i <= m; i++){
            long long money = 0;
            int p = 0, cnt = 0;
            
            for(int j = 1; j <= n; j++)f[j] = j;        
            for(int j = 0; j < (int)K[i].size(); j+=2){
                int u = K[i][j], v = K[i][j+1];
                if(!check(u, v)){
                    Union(u,v);
                    cnt++;
                }            
            }    
            cnt = n - 1 - cnt;
            for(int j = 1; j <= q; j++){
                int u = N[j].u, v = N[j].v;
                if(!check(u, v)){
                    Union(u, v);
                    money += N[j].co;
                    p++;
                }
                if(cnt == p)break;
            }
            ans = min(ans, (long long)money+a[i]);
        }
        cout<<ans<<endl;
    }
  • 相关阅读:
    Linux下状态查看相关命令
    Linux免密登录理解
    Linux下远程访问&拷贝&下载
    初识NAT、桥接和Host-Only
    Linux文件和文件夹权限管理
    Linux用户和用户组的操作
    Mac+Parallels+iTerm安装配置Linux Centos7
    SSM整合事务失效
    Linux用户和用户组管理命令
    Linux中{ }的用法
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/8457484.html
Copyright © 2020-2023  润新知