现在有个(可重边)无向图,无向图的每条边上都有一定数目的守卫,你现在想派人去炸掉这个图的一条边,是的该图不连通。但是你只能炸1条边且如果该边守卫为x人,那么你至少要派x个人过去。所以现在问你最少需要派多少人出发?
思路:就是求一个有重边的无向图的桥,有几个比较坑的地方
1,所给的图可能不连通,且不连通的时候不需要炸,输出0
2,当所要去炸的桥上的守卫数=0时,需要输出1而不是0
3,有重边
我的思路很简单,如果有重边的话那么就一定不是桥,那么只需要给一个特别一点值,在dfs里面更新的时候判断如果是这个特别的值就可以跳过了。在网上搜的题解都是转成有向图的做法,每条无向边转成两条有向边,..我还不是很懂..以后再回来看吧
//*我的代码*//
#include
#include
#include
using namespace std;
const int maxn=1500+10;
const int INF = 100000000;
int ans;
int n,m;
int dfs_clock;//时钟,每访问一个节点增1
vector G[maxn];//G[i]表示i节点邻接的所有节点
int pre[maxn];//pre[i]表示i节点被第一次访问到的时间戳,若pre[i]==0表示i还未被访问
int low[maxn];//low[i]表示i节点及其后代能通过反向边连回的最早的祖先的pre值
bool iscut[maxn];//标记i节点是不是一个割点
int adj[maxn][maxn];
int pointnum;
//求出以u为根节点(u在DFS树中的父节点是fa)的树的所有割顶和桥
//初始调用为dfs(root,-1);
int dfs(int u,int fa)
{
int lowu=pre[u]=++dfs_clock;
int child=0; //子节点数目
for(int i=0; i=pre[u])
{
iscut[u]=true; //u点是割顶
if(lowv>pre[u] && adj[u][v]!=-2) //(u,v)边是桥
ans = min(ans,adj[u][v]);
}
}
else if(pre[v]
//
一个大牛的做法,附上解释
分析:
本题的本质还是无向图求桥,且求得是守卫数目最少的那个桥。但是本题有3个点要注意:
1.所给的图可能不连通,且不连通的时候不需要炸,输出0.
2.当所要去炸的桥上的守卫数=0时,我们需要派的人数是1不是0.
3.任意两个节点u与v之间可能存在多条边。
对于上面的1与2点,我们在原始tarjan()函数运行完后加一些判断就能解决.
不过对于重边无向图,首先我们要用邻接表来保存图了(不能再用vector的邻接矩阵了).
然后之前无重边的时候我们都是用过fa来标记父节点的,如果u的儿子等于fa,那么直接跳过。即如果u不通过儿子连回fa的话,low[u]==pre[u]肯定>pre[fa]。现在本题其实u是可以通过另一条(fa,u)的边连回fa的,所以这里即使u不通过儿子连回fa的话,low[u]==也可以==pre[fa]。因为fa通过边1到u,u可以通过边2到fa。
所以本题把无向图转换成有向图来做:
把每条无向边分为两条有向边i与i+1,如果u通过边i到达了v,那么v中必然有一条边是i^1且可以通过该i^1边到u.所以如果在v节点遍历时到达i^1边时,我们直接跳过.
具体实现还是需要体会代码才能清晰.
#include
#include
#include
using namespace std;
const int maxn=1000+10;
const int maxm=2*1000*1000+100;
int n,m;
int tot;
int head[maxn];
struct Edge
{
int to,next,w;
}edges[maxm];
void add_edge(int u,int v,int w)
{
edges[tot]=(Edge){v,head[u],w};
head[u]=tot++;
edges[tot]=(Edge){u,head[v],w};
head[v]=tot++;
}
int pre[maxn],low[maxn];
int dfs_clock,point_num;
int ans;
void tarjan(int u,int E)
{
low[u]=pre[u]=++dfs_clock;
for(int e=head[u];e!=-1;e=edges[e].next)
{
int v=edges[e].to;
if(e==(E^1)) continue;
if(!pre[v])
{
tarjan(v,e);
low[u]=min(low[u],low[v]);
if(low[v]>pre[u])
ans=min(ans,edges[e].w);
}
else low[u]=min(low[u],pre[v]);
}
point_num++;
}
int main()
{
while(scanf("%d%d",&n,&m)==2&&n)
{
ans=1000000;
dfs_clock=point_num=tot=0;
memset(pre,0,sizeof(pre));
memset(head,-1,sizeof(head));
for(int i=0;i