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;
}