图算法习题

通用汇点

算法导论22.1-6
思路:通用汇点k是邻接矩阵中对应的那一行全为0,对应的一列全为1(akk=0除外),它满足这样的条件:aik=0,akj=1(j!=k)。只要有aij=1,则i不可能是通用汇点(通用汇点不能有出边);如果aij=0,则j不可能是(通用汇点必须有入边)。这样可以想象为从矩阵的左上角开始,查看aij的值,如果是1,则往下走;如果是0则往右走。直到超出了矩阵范围。那么超出范围之前有两种情况:

  1. i=n-1且aij=1,这样在走的过程中,每一行至少有一个1,与“通用汇点k是邻接矩阵中对应的那一行全为0”矛盾,所以图中不存在通用汇点;
  2. j=n-1且aij=0,这样在走的过程中,每一列至少有一个0且0~i-1行中每一行至少有一个1。类似1中的推论,k不可能是[0,i-1]。 而由于对于所有的p,存在满足q<=i的q,apq=0,则[i+1,n-1]不可能是通用汇点,因为如果是,则与通用汇点“对应的一列全为1(akk=0除外)”矛盾。所以只有此时的i可能是通用汇点,在根据通用汇点的条件“通用汇点k满足这样的条件:aik=0,akj=1(j! =k)” 最后判断它是不是通用汇点。

设n为点的个数,判断是否存在通用汇点见下面的算法.
通用汇点算法

上面的算法在矩阵中指针游走时,不管aij取值是0还是1,都能使得i指针或者j指针前移,最多花费2n的时间到达邻邻接矩阵外部,这样在O(V)的时间内是能完成判断的。而当确定i了之后,有两个并列的循环,它们分别耗费时间为O(n),所以总体耗费时间也是O(n)。

摔跤手分配

算法导论22.2-7

把有竞争关系的对手之间连上边,则题目可以转换为设有红蓝两色,是否存在一颗广度优先树,它的每一层的颜色都不同。

先利用给定信息构建邻接表,耗费的时间复杂度是O(n+r)。然后以第一个节点(定为红色)为源点进行广度优先遍历,对于邻接表中的Adj[u]里的每个节点v,如果u的颜色是红色,
1)v未处理,则将v置为蓝色;
2)如果v是红色,则冲突,返回false;
3)如果v是蓝色,则可不做处理。
反之,如果u是蓝色,则依次类推。
另外增加一个白色代表未处理。

适当修改书中的广度优先遍历算法BFS,得到给图着色的算法:
摔跤手算法

如果算法返回的true,则根据颜色将点分为两类,也就是把选手分为娃娃脸和高跟鞋两类。

综上,构造邻接表所需的时间为O(n+r),着色复杂度为O(n+r),根据已有的着色来进行分类的复杂度为O(n)。所以总体的复杂度为O(n+r)。

树的直径

算法导论22.2-8

先以任意一点s作为源点进行广度优先遍历,然后找到距离s的点x,再以x为源点进行广度优先遍历,得到的最大距离即是树的直径,见下面的算法。算法调用BFS的复杂度为O(V+E),找到最大的d,复杂度为O(V),所以总体的复杂度为O(V+E)。

树的直径算法

下面证明经过两次BFS得到的一定是最长的距离。第一次BFS的起点和终点分别是s和x,设真正的直径端点为m和n,p(s,x)代表s走到x的路径,d(a,b,c)代表经过a、b、c三点的路径的长度。 根据s 是否在直径上和p(s,x)是否和直径相交分为三种情况讨论,证明x一定会在直径上,示意图可以参见图:

证明第一次BFS得到的点一定在直径上的示意图

  1. s在直径上。用反证法证明:如果x不在直径上,则根据第一次BFS有d(s,x)>d(s,m),从而有d(n,s,x)>d(n,s,m),即d(n,x)>d(n,m),这和mn是直径的条件矛盾,所以x一定会在直径上。
  2. s不在直径上,且p(s,x)与p(m,n)相交。用反证法证明:如果x不在直径上,设p(s,x)与p(m,n)相交于点w,根据第一次BFS有d(s,w,x)>d(s,w,m),即d(w,x)>d(w,m),从而d(n,w,x)>d(n,w,m),也就是存在mx路径比直径mn还要长,这与mn是直径的条件矛盾。所以x一定会在直径上。
  3. s不在直径上,且p(s,x)不与p(m,n)相交。用反证法证明:由于树是连通图,所以p(s,x)和p(m,n)一定会通过一条路径相连,假设在p(s,x)上的点w和在p(m,n)上的点y之间有一条路径。根据第一次BFS有d(s,w,x)>d(s,w,y,m),即d(w,x)>d(w,y,m),所以d(n,y,w,x)>d(n,y,m),这和mn是直径的条件矛盾,所以x一定会在直径上。

证明了点x在直径上面,则x一定会是直径上的一个端点。因为第一次BFS得到的x一定是度为1(相当于叶节点)的点,否则与x是距离s 最远的点矛盾。

因为点x是直径的一个端点,所以第二次BFS以x为起始点进行BFS,得到的最大距离就是树的直径。

转载于:https://www.cnblogs.com/FannyChung/p/4954942.html

算法sicily例题 1000. sicily 1155. Can I Post the lette Time Limit: 1sec Memory Limit:32MB Description I am a traveler. I want to post a letter to Merlin. But because there are so many roads I can walk through, and maybe I can’t go to Merlin’s house following these roads, I must judge whether I can post the letter to Merlin before starting my travel. Suppose the cities are numbered from 0 to N-1, I am at city 0, and Merlin is at city N-1. And there are M roads I can walk through, each of which connects two cities. Please note that each road is direct, i.e. a road from A to B does not indicate a road from B to A. Please help me to find out whether I could go to Merlin’s house or not. Input There are multiple input cases. For one case, first are two lines of two integers N and M, (N<=200, M<=N*N/2), that means the number of citys and the number of roads. And Merlin stands at city N-1. After that, there are M lines. Each line contains two integers i and j, what means that there is a road from city i to city j. The input is terminated by N=0. Output For each test case, if I can post the letter print “I can post the letter” in one line, otherwise print “I can't post the letter”. Sample Input 3 2 0 1 1 2 3 1 0 1 0 Sample Output I can post the letter I can't post the letter Source Code #include #include using namespace std; int n,m; vector vout[200]; bool visited[200]; bool flood(int u) { visited[u]=1; if (u==n-1) return 1; for (int x=0; x<vout[u].size(); x++) { int &v=vout[u][x]; if (!visited[v] && flood(v)) return 1; } return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值