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寒假第七测的主要内容,如果未能解决你的问题,请参考以下文章