题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4005

In the war, the intelligence about the enemy is very important. Now, our troop has mastered the situation of the enemy's war zones, and known that these war zones can communicate to each other directly or indirectly through the network. We also know the enemy is going to build a new communication line to strengthen their communication network. Our task is to destroy their communication network, so that some of their war zones can't communicate. Each line has its "cost of destroy". If we want to destroy a line, we must spend the "cost of destroy" of this line. We want to finish this task using the least cost, but our enemy is very clever. Now, we know the network they have already built, but we know nothing about the new line which our enemy is going to build. In this condition, your task is to find the minimum cost that no matter where our enemy builds the new line, you can destroy it using the fixed money. Please give the minimum cost. For efficiency, we can only destroy one communication line. 
 
题意:n个点m条边,无向图,每条边有一个值,如果我们删除这条边,我们需要花费的金额等同这条边上的值。最开始整个图是连通的,现在会加上一条未知的边进去形成新图,我们只能删除一条边,保证新图不连通,求需要的最小金额是多少。
 
解法:
无向图求连通分量。我们首先应该知道,因为加入的边未知,所以我们所求的最小金额就是无论加入的边在图中哪里,我们都可以删除一条边来使它不连通。so我们首先对图求解连通分量,然后缩点,形成一棵树。这时候,我们可以想到,在加入一条未知的边之后会形成一个环,显然最小值的边不是我们的答案,因为这条边有可能就在这个环中,这时候我们就删除不了边了(其他边的值都比这个值大)。
我们仔细想想可以发现:根据题意构造最优路径,一条路径通过以结点u为根的子树时,一定会经过以结点u为根的子树中边权最小的那条边,那么这时候我们除去这条路径后剩下的边权中的最小值就是我们要求的答案了。所以,我们的算法思想就是:递归求解每个结点为根的子树中的最小边和次小边,我们必须保证这里最小边和次小边不可能在一条路径上,然后求次小边中的最小值就是答案了。
 
总结:
连通分量的一道很好的题,想了一天也没有好的解法方法,最后看了别人的代码和讲解才有一些理解和感悟,特别是在保证最小边和次小边不能有机会在一条路径上的解决方法上很巧妙。
 
最后,有两个疑问一直想不通,现在还一直在苦想中。。。
1:图中有重边,这时候我们要么全部保留,要么留下一条边权最大或最小的。这道题,我们需要全部保留,但为什么不是只留下一条边?
2:这道题进行缩点的时候,我用low[]数组判断RE了,好像不是可以用low来判断是否在一个连通块中吗?
图论题做得少,努力补充过程中。。。。图论很有意思,加油!
 
贴上整个代码,一些调试的和多余的函数代码没有删除,仔细理解应该没问题。
 
 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<vector>
#define inf 0x7fffffff
using namespace std;
const int maxn=+;
const int M = 2e5+;
int n,m;
struct Edge
{
int u,v,cost;
int next;
}edge[M];
int head[maxn],edgenum;
void add(int u,int v,int cost)
{
Edge E={u,v,cost,head[u] };
edge[edgenum]=E;
head[u]=edgenum++; Edge E1={v,u,cost,head[v] };
edge[edgenum]=E1;
head[v]=edgenum++;
} int pre[maxn],low[maxn],dfs_clock,bcc_cnt,index;
int mark[maxn];
vector< vector<Edge> > dfsmap;
vector<int> vec;
int color[maxn];
int dfs(int u,int fa)
{
low[u]=pre[u]= ++dfs_clock;
int flag=;
for (int i=head[u] ;i!=- ;i=edge[i].next)
{
int v=edge[i].v;
if (v==fa && flag) {flag=;continue; }
if (!pre[v])
{
dfs(v,u);
low[u]=min(low[u],low[v]);
}
else if (pre[v]<pre[u])
low[u]=min(low[u],pre[v]);
}
}
void tarjan(int u,int fa){
vec.push_back(u);
pre[u]=low[u]=index++;
mark[u]=true;
bool flag=true;
for(int i=head[u] ;i!=- ;i=edge[i].next){
int d=edge[i].v;
if(d==fa && flag){flag=false;continue;}
if(!pre[d]){
tarjan(d,u);
low[u]=min(low[u],low[d]);
}else {
low[u]=min(low[u],pre[d]);
}
}
if(low[u]==pre[u]){
int d;
bcc_cnt++;
do{
d=vec.back();
vec.pop_back();
color[d]=bcc_cnt;
mark[d]=false;
}while(d!=u);
}
}
void find_bcc()
{
memset(pre,,sizeof(pre));
memset(low,,sizeof(low));
memset(mark,false,sizeof(mark));
vec.clear();
dfs_clock=bcc_cnt=;
index=;
for (int i= ;i<=n ;i++)
if (!pre[i]) tarjan(i,-);
}
int mindistance;
pair<int,int> dfs2(int u,int fa)
{
int first=inf,second=inf;
for (int i= ;i<dfsmap[u].size() ;i++)
{
int v=dfsmap[u][i].v;
int w=dfsmap[u][i].cost;
if (v==fa) continue;
pair<int,int> tmp=dfs2(v,u);
if (tmp.first>w) swap(tmp.first,w);
//if (second>w) second=w;
if (tmp.first<first)
{
second=min(tmp.second,first);
first=tmp.first;
}
else if (tmp.first<second) second=tmp.first;
}
return make_pair(first,second);
}
int main()
{
int a,b,c;
while (scanf("%d%d",&n,&m)!=EOF)
{
memset(head,-,sizeof(head));
edgenum=;
for (int i= ;i<m ;i++)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
find_bcc();
cout<<endl<<bcc_cnt<<endl;
for (int i= ;i<=n ;i++)
cout<<i<<" "<<low[i]<<" "<<color[i]<<endl;
cout<<endl;
dfsmap.resize(n+);
for (int i= ;i<n+ ;i++) dfsmap[i].clear();
int mindist=inf,uu=,vv=;
for (int i= ;i<edgenum ;i++)
{
int u=edge[i].u;
int v=edge[i].v;
int w=edge[i].cost;
int u1=color[u] ,v1=color[v] ;
if (u1 != v1)
{
Edge E={u1,v1,edge[i].cost };
dfsmap[u1].push_back(E);
if (edge[i].cost<mindist)
{
mindist=edge[i].cost;
uu=u1 ;vv=v1 ;
}
}
}
// for (int i=1 ;i<=n ;i++)
// {
// int u=low[i];
// for (int j=head[i] ;j!=-1 ;j=edge[j].next)
// {
// int v=low[edge[j].v ];
// if (u!=v)
// {
// Edge E={u,v,edge[j].cost };
// dfsmap[u].push_back(E);
// if (edge[j].cost<mindist)
// {
// mindist=edge[j].cost;
// uu=u ;vv=v ;
// }
// }
// }
// }
mindistance=inf;
pair<int,int> p1=dfs2(uu,vv);
pair<int,int> p2=dfs2(vv,uu);
//pair<int,int> p1=dfs3(uu,vv);
//pair<int,int> p2=dfs3(vv,uu);
mindistance=min(mindistance,min(p1.second,p2.second));
printf("%d\n",mindistance==inf ? - : mindistance);
}
return ;
}

后续:感谢大牛提出宝贵的意见。。。。

hdu 4005 The war的更多相关文章

  1. HDU 4005 The war(双连通好题)

    HDU 4005 The war pid=4005" target="_blank" style="">题目链接 题意:给一个连通的无向图.每条 ...

  2. HDU 4005 The war Tarjan+dp

    The war Problem Description   In the war, the intelligence about the enemy is very important. Now, o ...

  3. HDU 4005 The war (图论-tarjan)

    The war Problem Description In the war, the intelligence about the enemy is very important. Now, our ...

  4. HDU 4005 The war 双连通分量 缩点

    题意: 有一个边带权的无向图,敌人可以任意在图中加一条边,然后你可以选择删除任意一条边使得图不连通,费用为被删除的边的权值. 求敌人在最优的情况下,使图不连通的最小费用. 分析: 首先求出边双连通分量 ...

  5. HDU 4005 The war(边双连通)

    题意 ​ 给定一张 \(n\) 个点 \(m\) 条边的无向连通图,加入一条边,使得图中权值最小的桥权值最大,如果能使图中没有桥则输出 \(-1\). 思路 ​ 先对原图边双缩点,然后变成了一棵树.在 ...

  6. hdu 4005(边双连通)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4005 思路:首先考虑边双连通分量,如果我们将双连通分量中的边删除,显然我们无法得到非连通图,因此要缩点 ...

  7. hdu 4005 双联通 2011大连赛区网络赛E *****

    题意: 有一幅图,现在要加一条边,加边之后要你删除一条边,使图不连通,费用为边的费用,要你求的是删除的边的最小值的最大值(每次都可以删除一条边,选最小的删除,这些最小中的最大就为答案) 首先要进行缩点 ...

  8. hdu 4005 边连通度与缩点

    思路:先将图进行缩点,建成一颗树,那么如果这是一条单路径树(即最大点度不超过2),就不在能删的一条边,使得不连通.因为将其头尾相连,形成一个圈,那么删任意一条边,图都是连通的. 上面的是无解的情况,如 ...

  9. HDU 4070 Phage War

    贪心,t 大的放到前面...因为感染所有cell需要的phage的总数是一定的,所以产生phage需要的时间是一定的,只需要考虑用来感染的时间,这样考虑的话,把 t 小的放后面的话,可以发现总时间的最 ...

随机推荐

  1. SublimeText快捷键大全(附GIF演示图)

    Sublime Text是码农必备之神器,有助于码农快速开垦,如果掌握了Sublime强大的快捷键就可以飞起来了.下面下载吧小编汇总了SublimeText支持的全部快捷键(适用SublimeText ...

  2. Python在金融,数据分析,和人工智能中的应用

    Python在金融,数据分析,和人工智能中的应用   Python最近取得这样的成功,而且未来似乎还会继续下去,这有许多原因.其中包括它的语法.Python开发人员可用的科学生态系统和数据分析库.易于 ...

  3. Mysql导入导出 改密命令总结(笔记三)

    一.从数据库导出数据 注意这些语句的执行是在在没进入mysql命令行之前,在mysql命令行不行 C:\Windows\system32>导出命令 而不是 Mysql>导出命令 1.导出整 ...

  4. 【easyui】—easyui教你编写一个前台的架子

    以前做项目都是在别人搭建好的环境下直接编写单独的页面,也没有处理过怎么搭建一个框架.看到别人的布局都挺好的,自己也想做一个走一下流程. 嘿,刚开始时看着别人写的代码,去找怎么写. 这是我自己的想法,使 ...

  5. USB设备驱动

    在Linux 内核中,使用usb_driver 结构体描述一个USB 设备驱动,usb_driver 结构体的定义如代码清单20.11 所示.代码清单20.11 usb_driver 结构体 stru ...

  6. video 测试

    https://segmentfault.com/a/1190000002401961  音量调节https://www.google.com/?gws_rd=ssl#newwindow=1& ...

  7. Node.js express路由简单分析

    这2天看了一点node+express的路由源码有了一点眉目,总结一下 对于app.get, 首先给出一张类图: 图1 注意每个路由有一个stack,这个stack中存放了Layer. 路由系统内有三 ...

  8. eclipse代码编辑快捷键

    代码提示(代码助手):alt + / 如输入e后按alt+/,则会出现以e开头的相关方法,写代码时经常按按 删除一行代码: 光标移动到该行任意位置,按ctrl+d 剪切:ctrl+x 复制:ctrl ...

  9. Debug.print的用法

    使用Debug.print可以用来更好的调试VBA程序 通过ALT+F11代开VBA编程窗口) 插入模块,接着在窗口中输入以下代码,按F5执行 Sub Excute() Debug.Print * + ...

  10. 在.net程序中使用System.Net.Mail来发送邮件

    System.Net.Mail是微软自家提供的工具,在.net程序中可以使用该空间中的SmtpClient实例来实现邮件的发送. 使用System.Net.Mail空间与Web.config配置相配合 ...