18寒假第七测

Posted Ed_Sheeran

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\\n");
    else
        printf("%lld\\n",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\\n");
        else printf("No\\n");
    }
    
}

第三题 先一个裸地最小生成树,在对选择每个公司进行模拟(在新图上连边),还需要新连的边一定在原生成树的边中,正确性易见,这样复杂度从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;
}

 

以上是关于18寒假第七测的主要内容,如果未能解决你的问题,请参考以下文章

寒假第七周 2.22 --- 2.28

寒假学习记录第七天

寒假集训第七天---综合

2020年寒假学习进度第七天

小刘同学的第七十篇博文

Gym .101879 USP Try-outs (寒假自训第七场)