图论 day 1 测试

百度地图上有n 个城市,城市编号依次为1 到n。地图中有若⼲个城市群,编号依次为1 到m。每个城市群
包含⼀个或多个城市;每个城市可能属于多个城市群,也可能不属于任何城市群。
地图中有两类道路。第⼀类道路是城市之间的快速路,两个城市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最小生成树

猜你喜欢

转载自blog.csdn.net/beloved_rancy/article/details/79344432