20170824图论选讲部分习题

1.车站分级

讲过啊,拓扑排序,每个停靠的车站向所有未停靠的车站连一条边,拓扑层数即可,小优化,每次删0度点的边时顺便统计一下删好后为0度点的边

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 1005
using namespace std;
int to[maxn][maxn],point[maxn],Map[maxn][maxn],x[maxn],v[maxn],a[maxn],b[maxn];
int ans=0,n,m;
void work()
{
    for(int i=1;i<=n;i++)
    if(!v[i]) point[++point[0]]=i;
    while(point[0])
    {
        ans++;
        while(point[0])
        {
            int k=point[point[0]];point[0]--;
            for(int i=1;i<=to[k][0];i++)
            {
                v[to[k][i]]--;
                if(!v[to[k][i]]) x[++x[0]]=to[k][i];
            }
        }
        for(int i=1;i<=x[0];i++)
        point[i]=x[i];
        point[0]=x[0];
        x[0]=0;
    }
    printf("%d\n",ans);
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&a[0]);
        b[0]=0;
        for(int i=1;i<=a[0];i++) scanf("%d",&a[i]);
        for(int i=1;i<a[0];i++)
            for(int j=a[i]+1;j<a[i+1];j++)
            b[++b[0]]=j;
        for(int i=1;i<=a[0];i++)
            for(int j=1;j<=b[0];j++)
            if(!Map[a[i]][b[j]])
            {
                Map[a[i]][b[j]]=1;
                v[b[j]]++;
                to[a[i]][++to[a[i]][0]]=b[j];
            }
    }
    work();
}

2.种树,这个我写过题解了

3.秦始皇的国家道路。先枚举选的是那条边,因为cnt总值最小肯定更优,我们用Prim求最小生成树可以接近最优值,考虑到加上选的边后的最小生成树是由原最小生成树换1条边的正确性可由Kruskal来证明吧。就是把最小生成树中u,v中的那条路径中最大的一条边换成枚举的那条边。

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
struct node{
    int x,y;
    double val;
}a[2000005];
int num1,num,f1,root;
int f[2000005],p[2000005],flag[2000005];
double dis[1005][1005],x[2000005],y[2000005];
int v[2000005],next[2000005],head[10005],vis[10005];
double v1[2000005];
int find(int u)
{
    if (f[u]!=u) f[u]=find(f[u]);
    return f[u];
}
void add(int a,int b,double val)
{
    num1++;
    v[num1]=b;
    v1[num1]=val;
    next[num1]=head[a];
    head[a]=num1;
}
bool cmp(node a,node b)
{
    return a.val<b.val;
}
void dfs(int u,double val)
{
    dis[root][u]=val;
    vis[u]=f1;
    for (int i=head[u]; i; i=next[i])
    {
        int V=v[i];
        if (vis[V]!=f1) dfs(V,max(val,v1[i]));
    }
}
int main()
{
int asdasdasdasd;
    int t;
    scanf("%d",&t);
    while (t--)
    {
        num1=0;
        num=0;
        int n;
        scanf("%d",&n);
        for (int i=1; i<=n; i++)
            head[i]=0;
        for (int i=1; i<=n; i++)
            scanf("%lf%lf%d",&x[i],&y[i],&p[i]);
        for (int i=1; i<=n; i++)
            for (int j=i+1; j<=n; j++)
            {
                double dis=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
                num++;
                a[num].x=i;
                a[num].y=j;
                a[num].val=sqrt(dis);
                /*num++;
                a[num].x=j;
                a[num].y=i;
                a[num].val=sqrt(dis);*/
            }
        sort(a+1,a+num+1,cmp);
        for (int i=1; i<=n; i++)
            f[i]=i;
        double ans=0;
        for (int i=1; i<=num; i++)
        {
            flag[i]=0;
            int fx=find(a[i].x);
            int fy=find(a[i].y);
            if (fx!=fy)
            {
                f[fx]=fy;
                //f[fx]=find(fx);
                ans+=a[i].val;
                flag[i]=1;
            }
        }
        for (int i=1; i<=num; i++)
            if (flag[i])
            {
                add(a[i].x,a[i].y,a[i].val);
                add(a[i].y,a[i].x,a[i].val);
            }
        f1=0;
        for (int i=1; i<=n; i++)
        {
            f1++;
            root=i;
            dfs(i,0);
        }
        double ans1=0;
        for (int i=1; i<=n; i++)
            for (int j=i+1; j<=n; j++)
                if ((p[i]+p[j])/(ans-dis[i][j])>ans1) ans1=(p[i]+p[j])/(ans-dis[i][j]);
        printf("%.2f\n",ans1);
    }
    return 0;
}
    

4.受欢迎的奶牛

Tarjan求强连通分量缩点

求度为0的个数,如果大于等于2个,无解,不然输出度为0的强连通分量的size

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<stack>
#define maxn 100100
using namespace std;
stack<int> S;
struct note{
    int u,v;
}edge[maxn];
bool instack[maxn];
int to[maxn*2],id[maxn],Time,ans,num,sc,head[maxn],visit[maxn],next[maxn*2],low[maxn],dfn[maxn],n,m,size[maxn];
void make_way(int u,int v)
{
    to[++num]=v;
    next[num]=head[u];
    head[u]=num;
}
void tarjan(int u,int fa)
{
    dfn[u]=low[u]=++Time;
    instack[u]=1;
    S.push(u);
    for(int ed=head[u];ed;ed=next[ed])
    {
        if(!dfn[to[ed]])
        {
            tarjan(to[ed],u);
            low[u]=min(low[u],low[to[ed]]);
        }else
        if(instack[to[ed]])
        low[u]=min(low[u],dfn[to[ed]]);
    }
    //cout<<u<<‘ ‘<<low[u]<<‘ ‘<<dfn[u]<<endl;
    if(low[u]==dfn[u])
    {
        sc++;
        int v;
        do{

            v=S.top();
            S.pop();
            instack[v]=0;
            id[v]=sc;
            size[sc]++;
        }while(v!=u&&!S.empty());
    }
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d",&edge[i].u,&edge[i].v);
        make_way(edge[i].u,edge[i].v);
    }
    for(int i=1;i<=n;i++)
    if(!dfn[i])
    {
        tarjan(i,0);
    }
    for(int i=1;i<=m;i++)
    if(id[edge[i].u]!=id[edge[i].v])
    visit[id[edge[i].u]]++;
    bool flag=0;
    for(int i=1;i<=sc;i++)
    {
        if(!visit[i])
        {
            if(flag)
            {
                cout<<0<<endl;
                return 0;
            }
            flag=1;
            ans=i;
        }
    }
    printf("%d\n",size[ans]);
 } 

6.矿场搭建

WA10分,待改

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
int n,m,cnt,num,tot,son_num,ans1,Time,T,cases,root;
ll ans2;
int head[500005],dfn[500500],low[500005],vis[500005];
bool cut[500005];
int Next[1000005],to[1000005];
void make_way(int u,int v)
{
    to[++num]=v;
    Next[num]=head[u];
    head[u]=num;
 }
 void tarjan(int u,int fa_edge)
 {
     low[u]=dfn[u]=++Time;
     for(int edge=head[u];edge;edge=Next[edge])
     if(edge^1!=fa_edge)
     {
         int v=to[edge];
         if(!dfn[v])
         {
             tarjan(v,u);
             low[u]=min(low[u],low[v]);
             if(low[v]>=dfn[u])
             {
                 if(u==root) son_num++;else cut[u]=1;
             }
         }else
        {
            low[u]=min(low[u],dfn[v]);
         }
     }
 }
 void dfs(int u)
 {
     vis[u]=T;
     if(cut[u]) return;
     cnt++;
     for(int edge=head[u];edge;edge=Next[edge])
     {
         if(cut[to[edge]]&&vis[to[edge]]!=T) num++,vis[to[edge]]=T;
         if(!vis[to[edge]]) dfs(to[edge]);
     }
  }
int main()
{
    int Case=0;
    while(~scanf("%d",&m)&&m)
    {
        Case++;
        memset(head,0,sizeof(head));
        memset(dfn,0,sizeof(dfn));
        memset(vis,0,sizeof(vis));
        memset(low,0,sizeof(low));
        memset(cut,0,sizeof(cut));
        Time=num=n=ans1=T=0;
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d %d",&u,&v);
            n=max(n,max(u,v));
            make_way(u,v);
            make_way(v,u);
        }
        for(int i=1;i<=n;i++)
        {
            if(!dfn[i])tarjan(root=i,0);
            if(son_num>=2)
            cut[root]=1;
            son_num=0;
        }
        ans1=0;
        ans2=1;
        for(int i=1;i<=n;i++)
            if(!vis[i]&&!cut[i])
            {
                T++;cnt=num=0;
                dfs(i);
                if(!num) ans1+=2,ans2*=cnt*(cnt-1)/2;
                if(num==1) ans1++,ans2*=cnt;
            }
        printf("Case %d: %d %lld\n",Case,ans1,ans2);
    }

}
时间: 2024-10-23 06:27:46

20170824图论选讲部分习题的相关文章

正睿OI DAY3 杂题选讲

正睿OI DAY3 杂题选讲 CodeChef MSTONES n个点,可以构造7条直线使得每个点都在直线上,找到一条直线使得上面的点最多 随机化算法,check到答案的概率为\(1/49\) \(n\leq k^2\) 暴力 \(n\geq k^2\),找点x,求直线l经过x,且点数最多,点数\(\geq k+1\),递归,否则再找一个 One Point Nine Nine 现在平面上有\(n\)个点,已知有一个常数\(D\). 任意两点的距离要么\(\leq D\),要么\(\geq 1.

玩转算法系列--图论精讲 面试升职必备(Java版)

第1章 和bobo老师一起,玩转图论算法欢迎大家来到我的新课程:<玩转图论算法>.在这个课程中,我们将一起完整学习图论领域的经典算法,培养大家的图论建模能力.通过这个课程的学习,你将能够真正地,玩转图论算法:) 第2章 图的基本表示千里之行,驶于足下.解决任何有一个图论算法问题,首先需要用基本的数据结构来表示图.在这一章,我们就将探索图的基本表示问题,学习邻接矩阵和邻接表,进而,也让同学们熟悉这个课程的整体代码风格. 第3章 图的深度优先遍历任何一种数据结构,都需要进行遍历.图也不例外.通过深

数据结构--图(中)--树之习题选讲Complete Binary Search Tree

Complete Binary Search Tree 完全 二叉 搜索数 题意理解 二叉搜索数 左小右大 完全二叉树 结构规律 完全二叉搜索数 到底用什么数据结构来表示这个树呢?链表还是数组. 1.由于是完全二叉树,所以我们能准确的算出来左子树有多少个结点.   完全二叉树+n个树 -> 左子树的个数 2.左子树的个数能推出根节点的大小,左子树4个,那么根节点一定是第5位数 左子树的个数->根节点的值 3.这个思维:当我们确定了根节点之后,我们可以很容易的通过递归来确定其他的结点      

[入门向选讲] 插头DP:从零概念到入门 (例题:HDU1693 COGS1283 BZOJ2310 BZOJ2331)

转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7326874.html 最近搞了一下插头DP的基础知识……这真的是一种很锻炼人的题型…… 每一道题的状态都不一样,并且有不少的分类讨论,让插头DP十分锻炼思维的全面性和严谨性. 下面我们一起来学习插头DP的内容吧! 插头DP主要用来处理一系列基于连通性状态压缩的动态规划问题,处理的具体问题有很多种,并且一般数据规模较小. 由于棋盘有很特殊的结构,使得它可以与“连通性”有很强的联系,因此插头DP最常见的应用要数

应用运筹学基础:组合优化 (6) - 近似算法选讲 (4)

这节课介绍了斯坦纳树问题(Steiner tree)与旅行商问题(TSP),并讲解了它们的近似算法. 平面上的斯坦纳树 平面上的斯坦纳树指的是这样的问题:平面上有 $n$ 个点,要用总长尽量少的线段把它们连通起来.要注意,线段不一定要在给定的 $n$ 个点相交(不然跑个最小生成树就没了),完全可以在平面上的其它点相交.最优解中,线段在平面上除了给定点外的交点称为斯坦纳点. 可以从上图看出 $n = 3$ 和 $n = 4$ 的情况,$S$.$S_1$ 和 $S_2$ 是斯坦纳点.$n = 3$

ZROI 19.08.02 杂题选讲

给出\(n\)个数,用最少的\(2^k\)或\(-2^{k}\),使得能拼出所有数,输出方案.\(n,|a_i|\leq 10^5\). 显然一个绝对值最多选一次.这个性质非常强. 如果所有都是偶数,可以直接除以\(2\). 否则\(1\)或\(-1\)必须选,暴力枚举选哪个然后递归,每层去重,发现最多只会递归\(\log a\)次.总复杂度\(O((n+a)\log n)\),等价于线段树上区间长度总和. \(n\)个数,每次可以花费\(1\)的代价给某个数\(+1\)或\(-1\),问变成不

「总结」杂题选讲

Bitwise Xor 我们可以发现一个序列中的最小的异或值是两个大小相邻的数的\(xor\)取\(min\). 那么我们对序列排序. 只需要计算相邻的\(xor\)是大于等于\(k\)的方案. \(dp[i]\)是以\(i\)结尾最小\(xor\)大于\(K\)的方案. 然后我们可以类似于用树状数组来搞最长升降转移. 这次用\(trie\)来转移. MOD Problem 大水题 \[\begin{aligned} ans&=\sum\limits_{i=1}^{n}n\ mod\ I\&

数学选讲 orz

质数筛法: 肯定有一个质因数是小于根号n的.这个东西是很明显的. 启发式分解: review :欧几里得算法的证明 a=bmodc  ==> a-k*c=b; 扩展欧几里得求得解为 |s|+|t|最小的解 分数工厂: 有 n 个正整数 a1, a2, · · · , an 和 m 个正整数 b1, b2, · · · , bm 定义分数 Q = a1 · a2 · · · an b1 · b2 · · · bm = A/ B ,其中 A 与 B 互质 处理 k 个询问,每个询问给出一个 M ,求

[提升性选讲] 树形DP进阶:一类非线性的树形DP问题(例题 BZOJ4403 BZOJ3167)

转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7337179.html 树形DP是一种在树上进行的DP相对比较难的DP题型.由于状态的定义多种多样,因此解法也五花八门,经常成为高水平考试的考点之一. 在树形DP的问题中,有这样一类问题:其数据范围相对较小,并且状态转移一般与两两节点之间的某些关系有关. 今天,我们就来研究一下这类型的问题,并且总结一种(相对套路的)解决大多数类型题的思路. 首先,我们用一道相对简单的例题来初步了解这个类型题的大致思路,以及一