bzoj2140对tarjan算法的一些理解
来源:互联网 发布:如何优化页面响应速度 编辑:程序博客网 时间:2024/04/29 04:04
最近,又理解了tarjan有了新的感悟,以前的tarjan删掉了,因为写的都是垃圾。。现在我感觉因该阔以了。。。。(题目分析在后面)
基础就不说了,网上一大堆。。说重点。。。
我对tarjan的大体理解就是。首先dfs一颗树在这颗树中我们只管前向边和后向边,横向边是要忽略的。嗯,所以看tarjan之前一定要把算法导论关于dfs的一些性质看好了再来理解就好了。。
对于tarjan最大的问题就在于
if (dfn[to] > dfn[temp])
{
low[temp] = min(low[temp], low[to]);
}
else
{
if (isinstack[to] == true)//这里是为了避免横向边
low[temp] = min(low[temp], dfn[to]);
}
这段代码为什么
if (isinstack[to] == true)//这里是为了避免横向边
low[temp] = min(low[temp], dfn[to]);
不能改成
if (isinstack[to] == true)//这里是为了避免横向边
low[temp] = min(low[temp], low[to]);
呢?对于求强联通分量这样写是对的但如果你要求割点或者是割边这样就是错的。为什么呢?
请看这组数据:
4 4代表有4个点,4条边
点1到点2//注意这些边都是无向边
点2到点3
点3到点4
点4到点2
很明显点2 就是一个割点。but当你改变正确写法时点2就不是了。。自己模拟一边把,从点1开始(虽然算法是从任意点开始都是可行的但是这最好从1开始,不然对于这个图不好找错)
嗯,所以对于正确写法你从任意点开始都是对的,但是对于错误写法,你从某些 点开始就是错的。。如果还不理解就看下面博客
http://www.cnblogs.com/c1299401227/p/5402747.html 看评论才是重点!!!!!
嗯,现在应该全都理解了。。。。由于递归很好写而且会容易爆栈就没写递归,写了个非递归。。。
下面说说此题分析。先开始女向男连边,输入m后是男向女连边。夫妻如果在同一个联通分量里就是unsafe。怎么想出来的先考虑只有2对夫妻。3对夫妻的情况运用km匹配的
思想思考一下就不难出解了。。还有用trie 存名字表hash拉拉。。注意名字是大小写乱入所以还写了个change函数.
#include<iostream>#include<cstdio>#include<algorithm>#include<string.h>#include<stack>using namespace std;struct triee{int son[53];int endnum;};struct edgee{int to;};triee trie[40000];edgee edge[24050];int first[8050], nextt[24050];int root, diantot=1,enddiantotnum=1,edgetot = 1;//到底是从1开始还是0想清楚int low[8055], dfn[8055],state[8055],belong[8055],stackk[8055],match[8055];bool isinstack[8055];stack<int>que;int dfsnum,circlenum,stacknum=-1;int change(char s){if (s >= 'A'&&s <= 'Z'){int q = s - 'A' + 'a' + 26;;return q;}elsereturn s;}int getnum(char *s){int len = strlen(s);int temp = root;for (int j = 0; j < len; j++){if (trie[temp].son[change(s[j]) - 'a'] == 0){int qqq = change(s[j]) - 'a';trie[temp].son[change(s[j]) - 'a'] = diantot++;}temp = trie[temp].son[change(s[j]) - 'a'];}if (!trie[temp].endnum)trie[temp].endnum = enddiantotnum++;return trie[temp].endnum;}void addedge(int a, int b){edge[edgetot].to = b;nextt[edgetot] = first[a];first[a] = edgetot;edgetot++;}void tarjan(int num){if (belong[num] != -1)return;bool ahead = false;dfn[num] = low[num] = dfsnum++; state[num] = 1;isinstack[num] = true; que.push(num); stackk[++stacknum] = num;while (!que.empty()){ahead = false;int temp = que.top();for (int i = first[temp]; i; i = nextt[i]){int to = edge[i].to;if (state[to] == 0){dfn[to] = low[to] = dfsnum++; state[to] = 1;isinstack[to] = true; que.push(to); stackk[++stacknum] = to;ahead = true;break;}}if (!ahead){if (temp == que.top()){for (int i = first[temp]; i; i = nextt[i]){int to = edge[i].to;if (dfn[to] > dfn[temp]){low[temp] = min(low[temp], low[to]);}else{if (isinstack[to] == true)//这里是为了避免横向边low[temp] = min(low[temp], dfn[to]);}}if (dfn[temp] == low[temp]){while (stackk[stacknum] != temp){int to = stackk[stacknum--];belong[to] = circlenum;isinstack[to] = false;}int to = stackk[stacknum--];belong[to] = circlenum;isinstack[to] = false;circlenum++;}}state[temp] = 2;que.pop();}}}int main(){int n;scanf("%d", &n);for (int i = 0; i < n; i++){char a[10], b[10];scanf("%s%s", a, b);int aa, bb;aa = getnum(a); bb = getnum(b);match[aa] = bb; match[bb] = aa;//根据getnum函数里的totnum可知女为奇数,男为偶数;addedge(aa, bb);}int m;scanf("%d", &m);for (int i = 0; i < m; i++){char a[10], b[10];scanf("%s%s", a, b);int aa, bb;aa = getnum(a); bb = getnum(b);addedge(bb, aa);}for (int i = 1; i < enddiantotnum; i++)belong[i] = -1;for (int i = 1; i < enddiantotnum; i++){tarjan(i);}for (int i = 1; i < enddiantotnum; i += 2){if (belong[i] == belong[match[i]])printf("Unsafe\n");elseprintf("Safe\n");}return 0;}/*这段代码与此题无关只是为了补充关于求割点和割边for(int i=2;i<=n;++i)//n当然就是点数啦。。。1是起点也就是根其他点位置在哪无所谓。。。。{int v=father[i];//这里的father[i]就是dfs的时候i的父亲(dfs出的是一颗树啦,虽然我们要看后向边,但是可以把它看成是一颗树吧。if(v==1)rootson++;//统计根节点子树的个数,根节点的子树个数>=2,就是割点else{if (low[i] >= dfn[v])//割点的条件is_cut[v] = true;//父亲是割点}}for(int i=1;i<=n;++i){int v=father[i];if(v>0&&low[i]>dfn[v])//桥的条件 printf("%d,%d\n", v, i);}*/
- bzoj2140对tarjan算法的一些理解
- [bzoj2140]稳定婚姻 Tarjan
- BZOJ2140 稳定婚姻 [Tarjan]
- 关于tarjan算法的一些理解(割点割边)
- LCA tarjan hdu 2586代码详细步骤(转)有助于对tarjan算法的的理解
- LCA的tarjan算法理解
- 对算法的一些学习和理解
- 对求欧拉回路算法的一些理解
- 对Dijkstra算法原理的一些理解
- 对Retinex算法的一些理解
- 对算法的一些笔记及理解
- 关于tarjan算法的一些理解(割边和割点)
- LCA的tarjan算法的理解
- LCA的tarjan算法的理解
- LCA的tarjan算法的理解
- LCA Tarjan算法理解
- tarjan算法理解
- Tarjan算法理解篇
- sql学习笔记(韩顺平)
- jquery 通配符和选择器
- ssh中子窗口关闭之后刷新父窗口的问题
- 正则表达式大总结
- 删除hbase表时 org.apache.hadoop.hbase.TableNotDisabledException 解决方法
- bzoj2140对tarjan算法的一些理解
- Windows7+cuda 7.5+vs2010
- Mac下配置Java环境变量
- 关于Eclipse中Java,JSP,JS,HTML等代码自动提示的设置
- shell学习笔记三
- 用串口下载程序的过程(现在写的不全面,以后再完善,第一次写博客)
- mybaits之dao层通用写法sqlsessiontemplate
- Android面试题整理-2
- JDBC实现增删查改操作