热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

poj3177RedundantPaths加入最少的边,使得无向图为一个双连通分支有重边

InordertogetfromoneoftheF(1<F<5,000)grazingfields(whicharenumbered1..F)t
In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the rest of the herd are forced to cross near the Tree of Rotten Apples. The cows are now tired of often being forced to take a particular path and want to build some new paths so that they will always have a choice of at least two separate routes between any pair of fields. They currently have at least one route between each pair of fields and want to have at least two. Of course, they can only travel on Official Paths when they move from one field to another. 

Given a description of the current set of R (F-1 <= R <= 10,000) paths that each connect exactly two different fields, determine the minimum number of new paths (each of which connects exactly two fields) that must be built so that there are at least two separate routes between any pair of fields. Routes are considered separate if they use none of the same paths, even if they visit the same intermediate field along the way. 

There might already be more than one paths between the same pair of fields, and you may also build a new path that connects the same fields as some other path.

Input

Line 1: Two space-separated integers: F and R 

Lines 2..R+1: Each line contains two space-separated integers which are the fields at the endpoints of some path.

Output

Line 1: A single integer that is the number of new paths that must be built.

Sample Input

7 71 2
2 3
3 4
2 5
4 5
5 6
5 7

Sample Output

2

Hint

Explanation of the sample: 

One visualization of the paths is: 
   1   2   3   +---+---+         |   |       |   | 6 +---+---+ 4      / 5     /     /  7 +
Building new paths from 1 to 6 and from 4 to 7 satisfies the conditions. 
   1   2   3   +---+---+     :   |   |   :   |   | 6 +---+---+ 4      / 5  :     /     :    /      : 7 + - - - - 
Check some of the routes: 
1 – 2: 1 –> 2 and 1 –> 6 –> 5 –> 2 
1 – 4: 1 –> 2 –> 3 –> 4 and 1 –> 6 –> 5 –> 4 
3 – 7: 3 –> 4 –> 7 and 3 –> 2 –> 5 –> 7
 
Every pair of fields is, in fact, connected by two routes. 

It's possible that adding some other path will also solve the problem (like one from 6 to 7). Adding two paths, however, is the minimum.




#include
#include
#include
#include
using namespace std;
//给你一个无向图,要求你加入最少的边,使得最后得到的图为一个双连通分支。
//所谓的双连通分支,即不存在桥的连通分支.
//可以求出所有的桥,把桥删掉。然后把所有的连通分支求出来,显然这些连通分支就是
//原图中的双连通分支。把它们缩成点,然后添上刚才删去的桥,就构成了一棵树。在树上添
//边使得树变成一个双连通分支即可
//只要求输出一共需要添加多少条边,统计度为1的节点(设共有x个),
//然后直接输出(x+1)/2即可.


///此题中有重边
const int maxn=80000;
//hash判重
int hash[maxn];
int repeat[maxn];
int ind[maxn];
void init_hash()
{
    memset(hash,-1,sizeof(hash));
    memset(repeat,0,sizeof(repeat));
    memset(ind,0,sizeof(ind));
}
int ishash(int u,int t,int index)//true 表示已经存在
{
    int tmp=u*10000+t;
    int ret=tmp%maxn;
    while(hash[ret]!=-1&&hash[ret]!=tmp)
    {
        ret=(ret+1)%maxn;
    }
    if(hash[ret]==tmp) return ind[ret];
    hash[ret]=tmp;
    ind[ret]=index;
    return -1;
}
struct edge
{
    int t,index;
    int next;
};
int V,E;
int p[maxn];
edge G[maxn];
int l;
void init()
{
    memset(p,-1,sizeof(p));
    l=0;
}
void addedge(int u,int t,int index,int l)
{
    G[l].t=t;
    G[l].index=index;
    G[l].next=p[u];
    p[u]=l;
}
int isbridge[maxn];
//tarjan 求割点 割边(没有重边)
int cut[maxn];//cut[i]非0表示i是割点
int color[maxn];//颜色:0表示没有访问,1表示正在访问,2表示访问结束
int lowc[maxn];//表示i及i的子孙相连的辈分最高的祖先节点所在的深度
int d[maxn];//表示i节点在树中的深度
int root;//根节点
int fath;//父节点
int pcnt;//割点个数
int egcnt;//割边个数
int egt[maxn];
int egu[maxn];
int egv[maxn];
void dfs(int u,int fath,int deep)
{
    color[u]=1;//正在访问
    lowc[u]=d[u]=deep;//深度
    int tot=0;//子树个数
    for(int i=p[u];i!=-1;i=G[i].next)
    {
        int t=G[i].t,index=G[i].index;
        if(t!=fath&&color[t]==1)
        {
            lowc[u]=min(lowc[u],d[t]);
        }
        if(color[t]==0)
        {
            dfs(t,u,deep+1);
            tot++;//子树加1
            lowc[u]=min(lowc[u],lowc[t]);
            //求割点
            //if((u==root&&tot>1)||(u!=root&&lowc[t]>=d[u])) cut[u]=1;//不能将pscnt++写到这里
            //求割边
            if(lowc[t]>d[u]) //edge[u][t]=true;  u->t是割边
            {
                //判断重边
                if(repeat[index])continue;
                egu[egcnt]=u;
                egv[egcnt]=t;
                egt[egcnt++]=index;
                isbridge[index]=1;
            }
        }
    }
    color[u]=2;
}
void calc()
{
    pcnt=egcnt=0;
    memset(color,0,sizeof(color));
    memset(lowc,0,sizeof(lowc));
    memset(d,0,sizeof(d));
    memset(cut,0,sizeof(cut));
    root=1;
    dfs(1,-1,1);
    //for(int i=1;i<=V;i++) if(cut[i]) pcnt++;
}
//去掉桥边 缩点
int tp[maxn];
edge tG[maxn];
int tl;
void taddedge(int u,int t,int index,int l)
{
    tG[l].t=t;
    tG[l].index=index;
    tG[l].next=tp[u];
    tp[u]=l;
}
int vis[maxn];
int belg[maxn];//节点i属于第几块
void find(int u,int id)
{
    vis[u]=1;belg[u]=id;
    for(int i=p[u];i!=-1;i=G[i].next)
    {
        int t=G[i].t,index=G[i].index;
        if(!isbridge[index]&&!vis[t])
        {
            find(t,id);
        }
    }
}
int Xdu1;
int du[maxn];//重建图后加点的度
void rebuildgraph()
{
    memset(tp,-1,sizeof(tp));
    tl=0;
    int det=0;//缩点后节点个数
    memset(vis,0,sizeof(vis));
    memset(belg,0,sizeof(belg));
    memset(du,0,sizeof(du));
    for(int i=1;i<=V;i++)
    {
        if(!vis[i])
        {
            find(i,++det);
        }
    }
    for(int i=0;i    {
        int u=egu[i],v=egv[i];
        int tu=belg[u],tv=belg[v];
        taddedge(tu,tv,i+1,tl++);
        taddedge(tv,tu,i+1,tl++);
    }
    //无向图 故最后度要除以2
    for(int i=1;i<=det;i++)
    {
        for(int j=tp[i];j!=-1;j=tG[j].next)
        {
            du[i]++;
            du[tG[j].t]++;
        }
    }
    Xdu1=0;
    for(int i=1;i<=det;i++)
    {
        if(du[i]/2==1) Xdu1++;
    }
}
int main()
{
    while(scanf("%d%d",&V,&E)==2)
    {
        init();
        init_hash();
        memset(isbridge,0,sizeof(isbridge));
        for(int i=1;i<=E;i++)
        {
            int u,t,index=i;
            scanf("%d%d",&u,&t);
            if(u>t) swap(u,t);
            int ret;
            if((ret=ishash(u,t,index))!=-1)
            {
                repeat[ret]=1;
                continue;
            }
            addedge(u,t,index,l++);
            addedge(t,u,index,l++);
        }
        calc();
        //删除桥边 缩点
        rebuildgraph();
        printf("%d\n",(Xdu1+1)/2);
    }
    return 0;
}

推荐阅读
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文讨论了如何在dotnet桌面(Windows)应用程序中添加图标。作者提到可以使用dotnet命令行工具与resource.rc文件一起使用来为标准.NET核心应用程序添加图标。作者还介绍了在创建控制台应用程序时如何编辑projeto1.csproj文件来添加图标。 ... [详细]
  • Ihavethefollowingonhtml我在html上有以下内容<html><head><scriptsrc..3003_Tes ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • GreenDAO快速入门
    前言之前在自己做项目的时候,用到了GreenDAO数据库,其实对于数据库辅助工具库从OrmLite,到litePal再到GreenDAO,总是在不停的切换,但是没有真正去了解他们的 ... [详细]
  • 本文介绍了pack布局管理器在Perl/Tk中的使用方法及注意事项。通过调用pack()方法,可以控制部件在显示窗口中的位置和大小。同时,本文还提到了在使用pack布局管理器时,应注意将部件分组以便在水平和垂直方向上进行堆放。此外,还介绍了使用Frame部件或Toplevel部件来组织部件在窗口内的方法。最后,本文强调了在使用pack布局管理器时,应避免在中间切换到grid布局管理器,以免造成混乱。 ... [详细]
  • 本文讨论了在使用Git进行版本控制时,如何提供类似CVS中自动增加版本号的功能。作者介绍了Git中的其他版本表示方式,如git describe命令,并提供了使用这些表示方式来确定文件更新情况的示例。此外,文章还介绍了启用$Id:$功能的方法,并讨论了一些开发者在使用Git时的需求和使用场景。 ... [详细]
  • fzu 1715 Ball and Box n个不同的求放到m个不同的盒子中方法的个数
    1715BallandBoxAccept:120Submit:288TimeLimit:1000mSecMemoryLimit:32768KBProblem ... [详细]
author-avatar
mobiledu2502883787
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有