拓扑排序,树的直径模板(CF14D 枚举删边)

HDU4607 树的直径

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
#define N 100005
#define INF 1<<30
int n,dis[N],E;
bool vis[N];
vector<int>G[N];
//注意点的标号是从0还是1开始的
int BFS(int x)
{
    int i;
    for(i=0;i<=n;i++)dis[i]=INF;
    memset(vis,0,sizeof(vis));
    queue<int>q;while(!q.empty())q.pop();

    q.push(x);
    dis[x]=0;
    while(!q.empty())
    {
        int u=q.front();q.pop();vis[u]=1;
        for(i=0;i<G[u].size();i++)
        {
            int v=G[u][i];
            if(dis[v]>dis[u]+1)
            {
                dis[v]=dis[u]+1;
                E=v;
                if(!vis[v])
                {
                    vis[v]=1;q.push(v);
                }
            }
        }
    }
    return E;
}
int main(){
    int T,i,que;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&que);
        for(i=0;i<=n;i++)G[i].clear();
        for(i=1;i<n;i++)
        {
            int a,b;scanf("%d %d",&a,&b);
            G[a].push_back(b);
            G[b].push_back(a);
        }
        E=BFS(1);
        E=BFS(E);
        while(que--)
        {
            int u;scanf("%d",&u);
            if(u<=dis[E]+1)printf("%d\n",u-1);
            else printf("%d\n",dis[E]+(u-(dis[E]+1))*2);//如果走过节点大于树直径上的点,要走回路(显然回路是走分支的部分,rt)直径+回路
        }
    }
    return 0;
}

Codeforces 14D Two Paths 树的直径

题意:给定一棵树

找2条点不重复的路径,使得两路径的长度乘积最大

思路:

1、为了保证点不重复,在图中删去一条边,枚举这条删边

2、这样得到了2个树,在各自的树中找最长链,即树的直径,然后相乘即可

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<set>
#include<vector>
#include<map>
#include<math.h>
#include<queue>
#include<string>
#include<stdlib.h>
#include<algorithm>
using namespace std;
#define N 220
struct Edge {
    int from, to, nex;
    bool hehe;
}edge[N<<1];
int head[N], edgenum;
void add(int u, int v){
    Edge E={u,v,head[u],true};
    edge[edgenum] = E;
    head[u] = edgenum ++;
}
int n;
int dis[N];
void init(){ memset(head, -1, sizeof head); edgenum = 0; }
int bfs(int x){
    memset(dis, 0, sizeof dis);
    dis[x] = 1;
    queue<int>q; q.push(x);
    int hehe = x;
    while(!q.empty()) {
        int u = q.front(); q.pop();
        for(int i = head[u]; ~i; i = edge[i].nex) {
            if(!edge[i].hehe)continue;
            int v = edge[i].to;
            if(dis[v])continue;
            dis[v] = dis[u]+1, q.push(v);
            if(dis[hehe]<dis[v])hehe = v;
        }
    }
    return hehe;
}
int main(){
    int i, u, v;
    while(~scanf("%d",&n)){
        init();
        for(i=1;i<n;i++){
            scanf("%d %d",&u,&v);
            add(u,v); add(v,u);
        }
        int ans = 0;
        for(i = 0; i < edgenum; i+=2)
        {
            edge[i].hehe = edge[i^1].hehe = false;
            u = edge[i].from; v = edge[i].to;
            int L1 = bfs(u); int R1 = bfs(L1);
            int mul1 = dis[R1] -1;
            int L2 = bfs(v); int R2 = bfs(L2);
            int mul2 = dis[R2] -1;
            ans = max(ans, mul1 * mul2);
            edge[i].hehe = edge[i^1].hehe = true;
        }
        printf("%d\n",ans);
    }
    return 0;
}

拓扑排序

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include <queue>
using namespace std;
const int maxn=30;
int exgcd(int a,int b,int &x,int &y){
    if(b==0){
        x = 1;
        y = 0;
        return a;
    }
    int r = exgcd(b,a%b,x,y);
    int t = x;
    x = y;
    y = t - a/b*y;
    return r;
}

int head[maxn],ip,indegree[maxn];
int n,m,seq[maxn];

struct note
{
    int v,next;
} edge[maxn*maxn];

void init()
{
    memset(head,-1,sizeof(head));
    ip=0;
}

void addedge(int u,int v)
{
    edge[ip].v=v,edge[ip].next=head[u],head[u]=ip++;
}

int topo()///拓扑,可做模板
{
    queue<int>q;
    int indeg[maxn];
    for(int i=0; i<n; i++)
    {
        indeg[i]=indegree[i];
        if(indeg[i]==0)
            q.push(i);
    }
    int k=0;
    bool res=false;
    while(!q.empty())
    {
        if(q.size()!=1)res=true;
        int u=q.front();
        q.pop();
        seq[k++]=u;
        for(int i=head[u]; i!=-1; i=edge[i].next)
        {
            int v=edge[i].v;
            indeg[v]--;
            if(indeg[v]==0)
                q.push(v);
        }
    }
    if(k<n)return -1;///存在有向环,总之不能进行拓扑排序
    if(res)return 0;///可以进行拓扑排序,并且只有唯一一种方式,seq数组即是排序完好的序列
    return 1;///可以进行拓扑排序,有多种情况,seq数组是其中一种序列
}
int main(){
    int x,y;
    int r = exgcd(23,5,x,y);
    r = exgcd(23,5,x,y);
    printf("%d %d %d",r,x,y);
    return 0;
}
时间: 2024-10-13 11:38:02

拓扑排序,树的直径模板(CF14D 枚举删边)的相关文章

算法笔记--树的直径模板

思路: 利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点. 先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c之间的距离就是树的直径. 模板: const int N=1e6+5; int head[N]; int dis[N]; bool vis[N]; int cnt=0,b,mxn=0; struct edge { int to,w,next; }edge[N]; void add_edge(int u,

light oj 1094 Farthest Nodes in a Tree(树的直径模板)

1094 - Farthest Nodes in a Tree PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB Given a tree (a connected graph with no cycles), you have to find the farthest nodes in the tree. The edges of the tree are weighted and undire

拓扑排序(待更新模板)

转载请注明出处:http://blog.csdn.net/u012860063?viewmode=contents ---------------------------------------------------------------------------------------------------------------------------------------------------------- 欢迎光临天资小屋:http://user.qzone.qq.com/593

树的直径模板

1 struct stu 2 { 3 int from,to,val,next; 4 }st[M]; //定义结构体储存节点和节点间的距离以及下一个节点的位置 5 6 7 void init() 8 { 9 num=0; 10 memset(head,-1,sizeof(head)); 11 } //初始化函数 12 13 14 void add_edge(int u,int v,int w) 15 { 16 st[num].from=u; //储存节点u 17 st[num].to=v; //

POJ 1985--Cow Marathon【树的直径 &amp;&amp; 模板】

Cow Marathon Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 4182   Accepted: 2116 Case Time Limit: 1000MS Description After hearing about the epidemic of obesity in the USA, Farmer John wants his cows to get more exercise, so he has com

BZOJ 1565 NOI2009 植物大战僵尸 最大权闭合图+拓扑排序

题目大意:给定一个m*n的草坪,每块草坪上的植物有两个属性: 1.啃掉这个植物,获得收益x(可正可负) 2.保护(r,c)点的植物不被啃掉 任何一个点的植物存活时,它左侧的所有植物都无法被攻击 求最大收益 首先这个保护和被保护的关系就是最大权闭合图的连边关系 然后直接跑就行 然后我们就会发现没过样例0.0 原因当图出现环时,根据题意,环上的所有点都不能取(想象一个无冷却的食人花前面放一个坚果) 所以这题还要去掉环 由于环上的点不能取,所以所有指向环上的点的点都不能取 这个条件看起来不太好做,我们

【模拟题(63550802...)】解题报告【贪心】【拓扑排序】【找规律】【树相关】

目录: 1.A[树相关]    2.B[找规律]    3.C[贪心][拓扑排序] A. 描述(A 输入文件 : A.input 输出文件 : A.output)一个城市的构成是一颗n 个节点的树(2 ≤ n ≤ 200), 现在需要在树中找出两条不相交的路径(即两条路径不能有重边也不能有重点),使得路径的长度的乘积最大.输入描述第一行一个数n 表示这个城市一共有 n 个节点.接下来 n-1 行,每行两个数ai 和bi (1 ≤ ai,bi ≤ n ),分别表示从ai 到bi,有一条边,每条边的

P3588 [POI2015]PUS(拓扑排序+线段树)

P3588 [POI2015]PUS 对于每个$(l,r,k)$,将$k$个位置向剩下$r-l-k+1$个位置连边,边权为$1$,这样就保证$k$个位置比剩下的大 先给所有位置填$1e9$保证最优 然后拓扑排序填数 填的数不在$[1,1e9]$内或者出现环,即为不合法 但是这样边数过多会超时 于是考虑线段树优化建图 把$n$个点建成线段树,每个节点向左右儿子连边,边权为0. 这样每次连一个区间$[l,r]$就只需要$log(r-l+1)$次 注意不合法情况要枚举完整 #include<iostr

拓扑排序 --- 模板题

确定比赛名次 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 10536    Accepted Submission(s): 4120 Problem Description 有 N个比赛队(1<=N<=500),编号依次为1,2,3,....,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排 名,但现在裁判委员会不能