求割点(无向边):
所谓的割点,就是删除某个点,图便不连通了。
POJ 1523
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int MN=1111;
struct Edge
{
int to,next;
}edge[MN<<2];
int dfn[MN];
int low[MN];
int head[MN<<2];
int subnet[MN];
int E,tp,root;
int vis[MN];
void Init()
{
memset(dfn,-1,sizeof(dfn));
memset(low,0,sizeof(low));
memset(head,-1,sizeof(head));
memset(subnet,0,sizeof(subnet));
memset(vis,0,sizeof(vis));
E=tp=0;
}
void Add(int a,int b)
{
edge[E].to=b;
edge[E].next=head[a];
head[a]=E++;
}
void tarjan(int u,int fa)
{
int son=0;
vis[u]=1;
dfn[u]=low[u]=++tp;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(vis[v]==1 && v!=fa)
low[u]=min(low[u],dfn[v]);
if(!vis[v])
{
tarjan(v,u);
son++;
low[u]=min(low[u],low[v]);
if((u==root && son>1) || (u!=root)&& dfn[u]<=low[v])
subnet[u]++;
}
}
vis[u]=2;
}
int main()
{
int i,cas=1,n,a,b,nodes;
while(scanf("%d",&n) && n)
{
nodes=n;
Init();
scanf("%d",&b);
Add(n,b);
Add(b,n);
while(scanf("%d",&a) && a)
{
scanf("%d",&b);
if(nodes<a) nodes=a;
if(nodes<b) nodes=b;
Add(a,b);
Add(b,a);
}
for(i=1;i<=nodes;i++)
{
if(dfn[i]==-1)
{
root=i;
tarjan(i,-1);
}
}
int flag=0;
printf("Network #%d\n",cas++);
for(i=1;i<=nodes;i++)
{
if(subnet[i]>=1)
{
flag=1;
printf(" SPF node %d leaves %d subnets\n",i,subnet[i]+1);
}
}
if(flag==0) printf(" No SPF nodes\n");
puts("");
}
}
求割边
HDU 4738(无向边)
http://acm.hdu.edu.cn/showproblem.php?pid=4738
题意:判断一个图是否联通,并给出每条边的权值,若联通则让你找出最小权值的割边。
注意:当所有边的权值为0的话且联通的话输出1,若不联通的话输出0
由于存储权值的数组开小了,所以超时。。。。超时。。。。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int MN=1010;
int dfn[MN],low[MN],num[MN];
int vis[MN],ww[MN*MN];
int tp,E;
int ans,cnt;
struct Edge
{
int next,to;
int tag;//判断是否有重边
int pos;//第几条边
int w;
} edge[MN*MN];
int head[MN*MN];
int bridge[MN*MN];
void init()
{
memset(dfn,-1,sizeof(dfn));
memset(low,0,sizeof(low));
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
E=tp=0;
}
int Add(int a,int b,int pos,int c)
{
for(int i=head[a]; i!=-1; i=edge[i].next)
{
if(edge[i].to==b)
{
edge[i].tag++;
return true;
}
}
edge[E].tag=0;
edge[E].w=c;
edge[E].pos=c;
edge[E].to=b;
edge[E].next=head[a];
head[a]=E++;
}
void tarjan(int u,int fa)
{
dfn[u]=low[u]=++tp;
vis[u]=1;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
int v=edge[i].to;
if(v==fa) continue;
if(!vis[v])
{
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u] && !edge[i].tag)
{
ww[++ans]=edge[i].w;
}
}
else
low[u]=min(low[u],dfn[v]);
}
}
int main()
{
int T,n,m,a,b,c;
while(scanf("%d%d",&n,&m))
{
if(n==0 && m==0) break;
init();
for(int i=1; i<=m; i++)
{
scanf("%d%d%d",&a,&b,&c);
Add(a,b,i,c);
Add(b,a,i,c);
}
ans=0;
tarjan(1,-1);
cnt=0;
for(int j=1; j<=n; j++)
{
if(!vis[j]) cnt++;
}
if(cnt) printf("0\n");
else
{
if(ans)
{
int MIN=99999999;
for(int i=1; i<=ans; i++)
{
if(MIN>ww[i]) MIN=ww[i];
}
if(MIN==0) printf("1\n");
else printf("%d\n",MIN);
}
else printf("-1\n");
}
}
return 0;
}
POJ 3177(无向图求)
题意:农场主有F片田野,他想把牛迁移,但是牛要是只走一条路的话会把这条路的草都吃没了,所以他想
从a到b之间有大于等于2的路。现在给你一个联通的图,问最少加多少条边能够让任意两点有大于等于2
条路可以走、
分析:求边双联通分量
求双联通分量然后缩点,再求缩点后的叶子几点,加的边就是(ans+1)/2;
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int MN=5010;
const int MM= 10011;
int low[MN],dfn[MN];
int instack[MM];
int subnet[MN],vis[MN];
int stap[MN],head[MM];
int degree[MN];
int belong[MN];
int tp,root;
int E,p;
int ans;
int cnt;
struct Edge
{
int to,next;
} edge[MM];
void Addedge(int a,int b)
{
for(int i=head[a]; i!=-1; i=edge[i].next)
{
if(edge[i].to==b)
{
return ;
}
}
edge[E].to=b;
edge[E].next=head[a];
head[a]=E++;
}
void Init()
{
memset(dfn,-1,sizeof(dfn));
memset(low,0,sizeof(low));
memset(head,-1,sizeof(head));
memset(degree,0,sizeof(degree));
memset(instack,0,sizeof(instack));
memset(belong,-1,sizeof(belong));
tp=E=p=0;
ans=cnt=0;
}
void tarjan(int x,int fa)
{
low[x]=dfn[x]=++tp;
stap[++p]=x;
instack[x]=1;
for(int i=head[x];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa) continue;
if(dfn[v]==-1)
{
tarjan(v,x);
if(low[x]>low[v])
low[x]=low[v];
}
else if(instack[v] && dfn[v]<low[x])
low[x]=dfn[v];
}
if(low[x]==dfn[x])
{
int top;
do
{
top=stap[p];
instack[top]=0;
belong[top]=cnt;
p--;
}
while(x!=top);
cnt++;
}
}
int main()
{
char s[100];
int i,j,n,m,a,b;
int cas=1;
while(scanf("%d%d",&n,&m)!=EOF)
{
Init();
for(i=1; i<=m; i++)
{
scanf("%d%d",&a,&b);
Addedge(a,b);
Addedge(b,a);
}
for(i=1; i<=n; i++)
{
if(dfn[i]==-1)
{
tarjan(i,-1);
}
}
for(i=1;i<=n;i++)
{
for(j=head[i];j!=-1;j=edge[j].next)
{
int x=belong[i];
int y=belong[edge[j].to];
if(x!=y)//当x和y不属于同一个缩点的时候
{
degree[x]++;
degree[y]++;
}
}
}
int res=0;
for(i=0;i<cnt;i++)//由于无向图每个点的度加了两次
{//当度是1的时候表明是叶子节点
if(degree[i]/2==1) res++;
}
// printf("Output for Sample Input %d\n",cas++);
printf("%d\n\n",(res+1)/2);
}
return 0;
}