枯木逢春不再茂,年少且惜镜边人
这周准备完结阿哈算法,其中有一章的学习不是很熟练(总之学的慢,忘的快。哎,真的,学完得好好从背包开始复习了,等复习完了,准备进行更深层次的学习,也就是从做题中获取知识,淦!像那个男人一样(shy))
首先看看图的割点
割点就是在图中找个点去掉,他的儿子回不去祖先哪里,那么这个点满足割点
给组例子
6 7
1 4
1 3
4 2
3 2
2 5
2 6
5 6
图大概是这样
#include<stdio.h>
int n,m,e[9][9],root;
int num[9],low[9],flag[9],index;
int min(int a,int b)
{
return a>b?b:a;
}
void dfs(int cur,int father)
{
int child=0,i;
index++;
num[cur]=index;
low[cur]=index;
for(i=1;i<=n;i++)
{
if(e[cur][i]==1)
{
if(num[i]==0)
{
child++;
dfs(i,cur);
low[cur]=min(low[cur],low[i]);
if(cur!=root&&low[i]>=num[cur])
flag[cur]=1;
if(cur==root&&child==2)
{
flag[cur]=1;
}
}
else if(i!=father)
{
low[cur]=min(num[i],low[cur]);
}
}
}
}
int main()
{
int i,j,x,y;
scanf("%d %d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
e[i][j]=0;
for(i=1;i<=m;i++)
{
scanf("%d %d",&x,&y);
e[x][y]=1;
e[y][x]=1;
}
root=1;
dfs(1,root);
for(i=1;i<=n;i++)
{
if(flag[i]==1)
{
printf("%d",i);
}
}
return 0;
}
运行结果大概是这样
那么简单的说一下,
这个dfs是怎么找呢
首先强调一下,他是通过避开他爸爸,去找路找他爷爷或者他爷爷的爷爷的…
对,是这样的,那么代码中是怎么实现去寻爷的呢
看下面
else if(i!=father)
{
low[cur]=min(num[i],low[cur]);
代码中可以看到这个吧
那这个呢就是避免了他碰到他爸爸,如果不是他爸爸,肯定是他爷爷或者…,那么就说明他可以不通过他爸爸回到他爷爷的身边,那么你就算他爸不管他,他爷爷也管他,不会饿死,相反 , 当你走到5号顶点时,儿子就会失道寡助,不知道怎么办,只能面对爸爸的噩梦,因为他想找爷爷没门路,所以他爸爸要是不管他,他就饿死了,他就玩不了LOL,他就成为不了那个男人,他就不能成为世界冠军,他就…对不起,扯远了,那么下面继续讲解
那么这个到底是干什么的呢?
low[cur]=min(low[cur],low[i]);
这个就是既然儿子找到去爷爷的路了 ,爸爸肯定得尾随,然后…对不起又扯远了了(感觉好像儿子去网吧被逮住了一样)
然后呢
就是判断了
那么 怎么判断呢
if(cur!=root&&low[i]>=num[cur])
flag[cur]=1;
if(cur==root&&child==2)
{
flag[cur]=1;
}
第一个if:如果他不是根节点那么他如果是割点的话,他儿子能找到的人只能是他爸爸,或者他哥哥,他姐姐,他表姐,他堂姐,他堂…,对不起又扯远了,不错,是不是觉得看起来长,哈哈哈哈,反着就是找不到他爷爷,当然他爷爷对应的值小,所以用大于等于弄,那么如果他是根节点(第二个 if),一个爸爸,没有爷爷,他只有两个儿子
,这两个儿子谁都找不到爷爷,那么 嘿嘿嘿 就只能乖乖写作业了
如果他是两个结点,那么这个时候,你就会问:
咱两谁爹谁儿子啊?
答:你die===我儿子;
额 , 这谁爹谁儿子都分不清
何来爷爷 额 我逻辑乱了到底谁爹谁儿子
好了,下来看看割边
其实只需要将
if(cur!=root&&low[i]>=num[cur])
flag[cur]=1;
大于等于删除等于,那么就好了
为什么呢?
你想想大于等于是能回到爸爸身边,现在等于都没有了,你回不到爷爷身边,也回不到爸爸身边,那么只能去哥哥姐姐那里了,哎
具体代码如下
#include<stdio.h>
int n,m,e[9][9],root;
int num[9],low[9],flag[9],index;
int min(int a,int b)
{
return a>b?b:a;
}
void dfs(int cur,int father)
{
int child=0,i;
index++;
num[cur]=index;
low[cur]=index;
for(i=1;i<=n;i++)
{
if(e[cur][i]==1)
{
if(num[i]==0)
{
child++;
dfs(i,cur);
low[cur]=min(low[cur],low[i]);
if(low[i]>num[cur])
printf("%d-%d\n",cur,i);
}
else if(i!=father)
{
low[cur]=min(num[i],low[cur]);
}
}
}
}
int main()
{
int i,j,x,y;
scanf("%d %d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
e[i][j]=0;
for(i=1;i<=m;i++)
{
scanf("%d %d",&x,&y);
e[x][y]=1;
e[y][x]=1;
}
root=1;
dfs(1,root);
return 0;
}
当然特殊情况就是根节点了,大佬们肯定可以很强的
可以发现变了的只有这一块
for(i=1;i<=n;i++)
{
if(e[cur][i]==1)
{
if(num[i]==0)
{
child++;
dfs(i,cur);
low[cur]=min(low[cur],low[i]);
if(low[i]>num[cur])
printf("%d-%d\n",cur,i);
}
else if(i!=father)
{
low[cur]=min(num[i],low[cur]);
}
只是去掉了根节点,为什么呢,因为根节点的话一个儿子,直接切,两个儿子,那么也是随便切,如果两个儿子不相互连接的话
下面看看 二分图最大匹配
二分图是无向图
#include<stdio.h>
int e[101][101];
int match[101];
int book[101];
int n,m;
int dfs(int u)
{
int i;
for(i=1;i<=n;i++)
{
if(book[i]==0&&e[u][i]==1)
{
book[i]=1;
if(match[i]==0||dfs(match[i]))
{
match[i]=u;
return 1;
}
}
}
return 0;
}
int main()
{
int i,j,t1,t2,sum=0;
scanf("%d %d",&n,&m);
for(i=1;i<=m;i++)
{
scanf("%d %d",&t1,&t2);
e[t1][t2]=1;
}
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
book[j]=0;
if(dfs(i))
{
sum++;
}
}
printf("%d",sum);
return 0;
}
那么是怎么得到的这样的代码的呢?
首先介绍一下匹配
给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。
极大匹配(Maximal Matching)是指在当前已完成的匹配下,无法再通过增加未完成匹配的边的方式来增加匹配的边数。最大匹配(maximum matching)是所有极大匹配当中边数最大的一个匹配。选择这样的边数最大的子集称为图的最大匹配问题。
如果一个匹配中,图中的每个顶点都和图中某条边相关联,则称此匹配为完全匹配,也称作完备匹配
那么二分图又是什么?
二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。
简单的说,一个图被分成了两部分,相同的部分没有边,那这个图就是二分图,二分图是特殊的图。
看一组例子
3 5
1 1
1 2
2 2
2 3
3 1
那么这个图可匹配成这样
1 -1
2 -2
3- -----
或者
1-2
2-3
3-2
显然第二种更对一些那么是怎么得到的呢?
首先
3没有男伴
那么找1 1有了怎么办 ,踢了一号女生
1号女生又找2号男生 2号男生 踢了 2号女生 只能找3号女生 1号男生说算了 和2号女生做吧
3号于是顺利成章的吃到了天鹅肉
那么这个过程是怎么实现的呢?
int dfs(int u)
{
int i;
for(i=1;i<=n;i++)
{
if(book[i]==0&&e[u][i]==1)
{
book[i]=1;
if(match[i]==0||dfs(match[i]))
{
match[i]=u;
return 1;
}
}
}
return 0;
}
当然dfs是关键
if(match[i]==0||dfs(match[i]))
{
match[i]=u;
return 1;
}
这块是判断他是不是匹配过了,或者这个男的(i)的女伴可以找到另一个舞伴,那么这个男的就空出来 供u女伴 那么这样下来,就是最大匹配
好了 今天就到这里了 ,阿哈算法也算基本完了,掌握不牢固,前面留了好多问题,以后开始解决,那么java也就可以开始学习了,但是算法只是入门,还的继续努力。