包含⼀个或多个城市;每个城市可能属于多个城市群,也可能不属于任何城市群。
地图中有两类道路。第⼀类道路是城市之间的快速路,两个城市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最小生成树