图论模板(持续更新)

1.tarjan(有向图强连通分量)(hdu5934缩点)

const int maxn=1e3+10;
int dfn[maxn],low[maxn],sta[maxn],vis[maxn],top,cnt; 
int in[maxn];
int color[maxn],sum;
// 染色数组用来缩点
//dfn[i]表示i是第几个搜到的,cnt用来计数编号 
//low[i]表示i及i的子孙中dfn的最小值
//sta表示栈数组,放的是当前强连通分量说包括的点
//vis[i]表示i是否在栈中 
vector <int> ve[maxn];//存图 
struct node
{
	int x,y,r,c;	
}bs[maxn]; 
void tarjan(int u)
{
   dfn[u]=low[u]=++cnt;
   sta[++top]=u;
   vis[u]=1;
   for(int i=0;i<ve[u].size();i++)
   {
   	  int v=ve[u][i];
   	  if(!dfn[v])
   	  {
   	     tarjan(v);	
   	   	 low[u]=min(low[u],low[v]);
	  }
	  else if(vis[v])
	    low[u]=min(low[u],low[v]);
   }
   if(dfn[u]==low[u])
   {
   	   color[u]=++sum;
   	   while(sta[top]!=u)
   	   {
   	   	 color[sta[top]]=sum;
   	     vis[sta[top--]]=0;	
	   }
	   vis[sta[top--]]=0;
   }
} 
int can(int a,int b)
{
	LL dis=(LL)(bs[a].x-bs[b].x)*(bs[a].x-bs[b].x)+(LL)(bs[a].y-bs[b].y)*(bs[a].y-bs[b].y);
	if(dis<=(LL)abs(bs[a].r)*(LL)abs(bs[a].r)) 
	   return 1;
	else 
	  return 0;
}
int main(void)
{
	int t;
	scanf("%d",&t);
	for(int cas=1;cas<=t;cas++)
	{
		int n;
		top=0;
		cnt=0;
		sum=0;
		scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
        	scanf("%d%d%d%d",&bs[i].x,&bs[i].y,&bs[i].r,&bs[i].c);
		    dfn[i]=0;
		    low[i]=0;
		    vis[i]=0;
			in[i]=0; 
		    ve[i].clear();
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(i==j) continue;
				if(can(i,j))
				{
					ve[i].push_back(j);
				}
			}	
		}
		for(int i=1;i<=n;i++)
		{
			if(!dfn[i])
			{
			  tarjan(i);
			} 	  	
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=0;j<ve[i].size();j++)
			{
				int to=ve[i][j];
				if(color[i]==color[to])
				   continue;
				in[color[to]]++;	
			}
		}
		int ans=0;
		for(int i=1;i<=sum;i++)
		{
			if(in[i]==0)
			{
				int cmin=1e4+10;
				for(int j=1;j<=n;j++)
				{
					if(color[j]==i)
					{
						cmin=min(cmin,bs[j].c);	
					}	
				}
				ans+=cmin;
			}
		}
	    printf("Case #%d: %d\n",cas,ans);			
	}
	return 0;
}

2.第k短路(Dijstra+A*)

const int N=1e3+7;
const int M=1e5+10; 
const int inf=0x3f3f3f3f;
int head[N],head1[N],cnt,cnt1,dis[N],k;
bool book[N];
struct node
{
	int to,w,next;
}E[M],E1[M];
struct Node
{
	int to,w;
	Node(){}
	Node(int to,int w):to(to),w(w){}
	friend bool operator <(Node a,Node b)
	{
		return a.w>b.w;
	}
};
struct NODE
{
	int to,w;
	NODE(){}
	NODE(int to,int w):to(to),w(w){}
	friend bool operator <(NODE a,NODE b)
	{
		return a.w+dis[a.to]>b.w+dis[b.to];
		//启发式函数,按当前距离+估价距离排序 
		// f = g + h
	}
};
inline void add(int u,int v,int w)
{
	E[cnt].to=v;
	E[cnt].w=w;
	E[cnt].next=head[u];
	head[u]=cnt++;
}
inline void add1(int u,int v,int w)
{
	E1[cnt1].to=v;
	E1[cnt1].w=w;
	E1[cnt1].next=head1[u];
	head1[u]=cnt1++;
}
inline int  dijs(int s,int e)
{
	memset(dis,inf,sizeof(dis));
	memset(book,0,sizeof(book));
	priority_queue<Node> q;
	q.push(Node(s,0));
	dis[s]=0;
	while(q.size())
	{
		Node now=q.top();
		q.pop();
		if(book[now.to]) continue;
		book[now.to]=1;	
		for(int i=head1[now.to];i!=-1;i=E1[i].next)
		{
			int to=E1[i].to;
			if(book[to]) continue;
			if(dis[to]>now.w+E1[i].w)
			{
				dis[to]=now.w+E1[i].w;
				q.push(Node(to,dis[to]));
			}
		}
	}
	if(dis[e]==inf)
	{
		return 1;		
	}
	return 0;	
}
inline int bfs(int s,int e)
{
	int cnt=0;
	priority_queue <NODE> q;
	q.push(NODE(s,0));
	while(q.size())
	{
		NODE now=q.top();
		q.pop();
		if(now.to==e)
		{
			k--;
			if(k==0)
				return now.w;
			//bfs时,如果第K次更新到终点,便是第K短路 
		}
		for(int i=head[now.to];i!=-1;i=E[i].next)
		{
			q.push(NODE(E[i].to,now.w+E[i].w));
		}
	}
	return -1;	
}
int main(void)
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		head[i]=head1[i]=-1;
	}
	cnt=cnt1=0;
	for(int i=0;i<m;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);
		add1(v,u,w);
	}
	int s,e;
	scanf("%d%d%d",&s,&e,&k);
	if(dijs(e,s))
	{
		printf("-1\n");
		return 0;
	}
	if(s==e) k++;
	printf("%d\n",bfs(s,e));
	return 0;	
}

 3.LCA(tarjan+并查集+离线查询)      

const int maxn=4e4+10;
bool vis[maxn];
int dis[maxn],f[maxn],head[maxn],lca[420],cnt;
//存图 
struct node
{
	int to,w;
	node(){}
	node(int to,int w):to(to),w(w){}
};
//给询问建图 
struct Node
{
	int u,v;
	int id;//用来存是第几个询问 
	int next;
}que[420];
vector<node> ve[maxn];
//建询问图加边 
void add(int u,int v,int w)
{
	que[cnt].u=u;
	que[cnt].v=v;
	que[cnt].id=w;
	que[cnt].next=head[u];
	head[u]=cnt++;	
}
//并查集维护 
int getf(int x)
{
	return f[x]==x?x:f[x]=getf(f[x]);
}
//tarjan算法 
void tarjan(int u,int fa)
{
	for(int i=0;i<ve[u].size();i++)
	{
		int v=ve[u][i].to;
		if(v==fa) continue;
		//根到当前节点的距离 
		dis[v]=dis[u]+ve[u][i].w;
		tarjan(v,u);
		//把u的子树合并到u上 
		f[getf(v)]=u;	
	}
	//标记已遍历 
	vis[u]=1;
	//处理询问 
	for(int i=head[u];i!=-1;i=que[i].next)
	{
		//如果v被遍历过,那么与u的LCA就是v的当前祖先 
		if(vis[que[i].v])
		{
			lca[que[i].id]=getf(que[i].v);	
		}
	}
	
}
int main(void)
{
	
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,m;
		cnt=0;
		scanf("%d%d",&n,&m);
		//初始化 
		for(int i=1;i<=n;i++)
		{
		   ve[i].clear();	
		   dis[i]=0;
		   vis[i]=0;
		   f[i]=i;
		   head[i]=-1;
		} 
		for(int i=1;i<n;i++)
		{
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			ve[u].push_back(node(v,w));
			ve[v].push_back(node(u,w));
		}
		
		//建询问图 
		for(int i=0;i<m;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			add(u,v,i);
			add(v,u,i);
		}
		tarjan(1,0);
		//建图的时候对于同一个询问建了两条边,所以i+=2 
		for(int i=0;i<cnt;i+=2)
		{
			int u,v,id;
			u=que[i].u;
			v=que[i].v;
			id=que[i].id;
			printf("%d\n",dis[u]+dis[v]-2*dis[lca[id]]);	
		}
	}
	return 0;
}

     

                                                                                                                                                                                                                                                                                                                                                                                                                          

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值