包含⼀个或多个城市;每个城市可能属于多个城市群,也可能不属于任何城市群。
地图中有两类道路。第⼀类道路是城市之间的快速路,两个城市u; v 之间增加⼀条距离为c 的边;第⼆类道
路是城市群之间的⾼速路,连接两个城市群a; b,通过这条⾼速路,城市群a ⾥的每个城市与城市群b ⾥的
每个城市之间两两增加⼀条距离为c 的边。图中所有边均为⽆向边。
你需要计算从城市s 到城市t 的最短路。
#include<stdio.h> #include<algorithm> #include<stack> #include<queue> #include<vector> #include<string.h> using namespace std; const int MAXN=20000; long long INF; struct Edge{ int to; long long val; Edge *nxt; }pool[MAXN*10],*tail=pool,*head[MAXN*3]; void addedge(int from,int to,long long val){ Edge *nd=tail++; nd->to=to; nd->val=val; nd->nxt=head[from]; head[from]=nd; } long long dis[MAXN*4],ex[MAXN*4]; struct node{ int dis,num; node(int a=0,int b=0):dis(a),num(b){} bool operator < (const node &a) const { return dis>a.dis; } }; priority_queue<node> q; int main(){ freopen("map.in","r",stdin); freopen("map.out","w",stdout); int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int k; scanf("%d",&k); for(int j=1;j<=k;j++){ int x; scanf("%d",&x); addedge(x,n+i,0); addedge(n+m+i,x,0); } } int m1,m2; scanf("%d",&m1); for(int i=1;i<=m1;i++){ int u,v,c; scanf("%d%d%d",&u,&v,&c); addedge(u,v,c); addedge(v,u,c); } scanf("%d",&m2); for(int i=1;i<=m2;i++){ int u,v,c; scanf("%d%d%d",&u,&v,&c); addedge(u+n,v+n+m,c); addedge(v+n,u+n+m,c); } int s,t; scanf("%d%d",&s,&t); memset(dis,60,sizeof(dis)); INF=dis[t]; dis[s]=0; q.push(node(0,s)); while(!q.empty()){ node nd=q.top(); q.pop(); int u=nd.num; if(ex[u]) continue; ex[u]=1; for(Edge *it=head[u];it;it=it->nxt){ int v=it->to; if(dis[u]+it->val<dis[v]){ dis[v]=dis[u]+it->val; q.push(node(dis[v],v)); } } } if(dis[t]==INF) printf("-1"); else printf("%I64d",dis[t]); }
建一个出点一个入点再spfa
jyb 给⼤家讲过强连通分量,强连通分量中的任意两点之间都可以互相到达。这个条件感觉很苛刻,⼤部分图
都不能满⾜。现在jyb 告诉你⼀个新的概念:单向连通图;如果有向图中,对于任意节点v1 和v2,⾄少存
在从v1 到v2 和从v2 到v1 的路径中的⼀条,则为单向连通图。现在给出若⼲个有向图,jyb 想问你它们是
不是单向连通图。
Input
第1 ⾏,1 个整数T, 表⽰数据组数,对于每组数据:
第1 ⾏,2 个整数n;m,表⽰点数和边数
接下来m ⾏,每⾏2 个整数u,v, 表⽰u 到v 有⼀条单向边。题⽬保证u! = v
Output
对于每组数据,如果是则输出”Yes”, 不是则输出”No”(均不含引号)
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; const int maxn1=200005; int sta[maxn1],ru[maxn1],headd[maxn1],tovv[maxn1],nxtt[maxn1],color[maxn1],stk[maxn1],head[maxn1],tov[maxn1],nxt[maxn1],low[maxn1],dfn[maxn1]; bool vis[maxn1]; int n,m,t,tot=0,top=0,idx=0,cnt=0,tott=0; void add2(int i,int j) { tott++; tovv[tott]=j; nxtt[tott]=headd[i]; headd[i]=tott; } void add(int i,int j) { tot++; tov[tot]=j; nxt[tot]=head[i]; head[i]=tot; } void tarjan(int u) { idx++; low[u]=dfn[u]=idx; vis[u]=1; stk[++top]=u; for (int i=head[u];i;i=nxt[i]) { int v=tov[i]; if (!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if (vis[v]&&low[u]>dfn[v]) low[u]=dfn[v]; } if (low[u]==dfn[u]) { cnt++; while (1) { int p=stk[top]; color[p]=cnt; top--; vis[p]=0; if (p==u) break; } } } void init() { memset(sta,0,sizeof(sta)); memset(ru,0,sizeof(ru)); memset(headd,0,sizeof(headd)); memset(tovv,0,sizeof(tovv)); memset(nxtt,0,sizeof(nxtt)); memset(head,0,sizeof(head)); memset(tov,0,sizeof(tov)); memset(nxt,0,sizeof(nxt)); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(color,0,sizeof(color)); memset(stk,0,sizeof(stk)); idx=cnt=tot=tott=top=0; } int main() { freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); scanf("%d",&t); while (t--) { init(); scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v); } for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i); for (int i=1;i<=n;i++) { for (int j=head[i];j;j=nxt[j]) { int v=tov[j]; if (color[i]!=color[v]) { add2(color[i],color[v]); ru[color[v]]++; } } } bool pd=1; int st=0,tp=0; for (int i=1;i<=cnt;i++) if (!ru[i]) sta[++tp]=i; while (st<tp) { if (tp-st>1) { pd=0; break; } int u=sta[++st]; for (int i=headd[u];i;i=nxtt[i]) { int v=tovv[i]; ru[v]--; if (!ru[v]) sta[++tp]=v; } } if (pd==1) printf("Yes\n"); else printf("No\n"); } return 0; }
tarjan缩点
cky 公司的运营蒸蒸⽇上,由于出差实在太频繁,⽽且坐汽车有些太慢了,所以cky 想要顺势直接进驻航空
业。cky 所在的国家天朝有n 个城市,m 个航空公司,每两个城市之间可能有⼀条航线运营(双向),⼀共
有k 条航线,每条航线都属于某⼀航空公司。现在cky 希望收购⼀家航空公司(为了涉⾜航空业以及防垄断,
cky 必须且只能购买⼀家航空公司),使得他能通过飞机从任意城市到达⽬的城市(允许转机),当然很可能
没有⼀家公司能满⾜cky 的要求,所以cky 还需收购其他公司掌控的航线。每个航空公司都有⼀个市值,每
条航线都有⼀个收购价。现在cky 想知道他最少需要花费多少钱。
Input
第1 ⾏,3 个整数n; m; k,表⽰城市数量,航空公司数和航线数。城市⽤1; 2; : : : ; n 编号。
接下来⼀⾏,⼀共m 个整数,第i 个整数ai 表⽰第i 个航空公司的市值。接下来k ⾏,每⾏4 个整数
ui; vi; costi; bi,表⽰第i 条航线连接城市u; v,价值costi,所属航空公司为bi
题⽬保证u! = v
题⽬保证有解。
Output
输出最少需要花费多少钱
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <cstdlib> #include <algorithm> #include <iostream> using namespace std; const int maxm = 200002; const int maxn = 2002; const long long INF = 1ll << 60; struct line { int u,v; long long w; bool operator < (const line &b) const { return w < b.w; } }l[maxm],mst[maxn]; struct edge { int u,v,next; }e[maxm]; int h[maxn],num; int fa[maxn]; long long a[maxn]; int n,m,k,cnt; long long ans; void build(int no,int u,int v) { num++; e[num].u = u; e[num].v = v; e[num].next = h[no]; h[no] = num; } int getfather(int x) { if(x == fa[x]) return x; else return fa[x] = getfather(fa[x]); } int main() { freopen("airplane.in","r",stdin); freopen("airplane.out","w",stdout); scanf("%d%d%d",&n,&m,&k); for(int i = 1; i <= m; i++) scanf("%I64d",&a[i]); int u,v,no,w; for(int i = 1; i <= k; i++) { scanf("%d%d%d%d",&u,&v,&w,&no); l[i].u = u; l[i].v = v; l[i].w = w; build(no,u,v); } sort(l+1,l+1+k); for(int i = 1; i <= n; i++) fa[i] = i; for(int i = 1; i <= k; i++) { int x = getfather(l[i].u); int y = getfather(l[i].v); if(x != y) { fa[y] = x; mst[++cnt] = l[i]; } } ans = INF; for(int i = 1; i <= m; i++) { for(int j = 1; j <= n; j++) fa[j] = j; for(int j = h[i]; j; j = e[j].next) { int x = getfather(e[j].u); int y = getfather(e[j].v); if(x != y) fa[y] = x; } long long res = 0; for(int j = 1; j <= cnt; j++) { int x = getfather(mst[j].u); int y = getfather(mst[j].v); if(x != y) { fa[y] = x; res += mst[j].w; } } if(res + a[i] < ans) ans = res + a[i]; } printf("%I64d\n",ans); return 0; }bst最小生成树