图论 [未完成 待续~待修改]
来源:互联网 发布:翅片式换热器计算软件 编辑:程序博客网 时间:2024/05/20 21:19
图的表示方法
矩阵
二维数组 map[i][j] 表示i到j的边 值为边得大小 ,定义一个值代表不存在这条边 一般为0
空间复杂度
vector
vectorG[N];
G[i][j] 表示有一条i->j的有向边
void add(int u,int v){ G[u].push_back(v);}
空间复杂度
前向星
struct edge{ int to,next,w;}G[N<<1];int head[N],tot;void add(int u,int v,int w){ G[tot].w=w,G[tot].to=v,G[tot].next=head[u],head[u]=tot++;}
空间复杂度
最短路
floyd
不解释
dijkstra
vector<pair<int ,int > >G[N];int d[N];int main(){ while(~scanf("%d%d",&m,&n)){ for(int i=1;i<=n;i++)d[i]=2e9+7,G[i].clear(); d[n]=0; for(int i=1,u,v,w;i<=m;i++){ scanf("%d%d%d",&u,&v,&w); G[u].push_back(make_pair(v,w)); G[v].push_back(make_pair(u,w)); } priority_queue<pair<int ,int> >q; q.push(make_pair(-d[n],n)); while(!q.empty()){ int u =q.top().second;q.pop(); for(int i=0,v;i<G[u].size();i++){ v=G[u][i].first; if(d[v]>d[u]+G[u][i].second){ d[v]=d[u]+G[u][i].second; q.push(make_pair(-d[v],v)); } } } if(d[n]==2e9+7) puts("-1"); else printf("%d\n",d[1]); } return 0;}
SPFA
vector<pair<int ,int > >G[N];int d[N],inq[N];int main(){ while(~scanf("%d%d",&m,&n)){ for(int i=1;i<=n;i++)d[i]=2e9+7,inq[i]=0,G[i].clear(); for(int i=1,u,v,w;i<=m;i++){ scanf("%d%d%d",&u,&v,&w); G[u].push_back(make_pair(v,w)); G[v].push_back(make_pair(u,w)); } queue<int >q; q.push(n);d[n]=0,inq[n]=1; while(!q.empty()){ int u =q.front();q.pop(); inq[u]=0; for(int i=0,v;i<G[u].size();i++){ v=G[u][i].first; if(d[v]>d[u]+G[u][i].second){ d[v]=d[u]+G[u][i].second; if(inq[v]==1) continue; inq[v]=0; q.push(v); } } } if(d[n]==2e9+7) puts("-1"); else printf("%d\n",d[1]); } return 0;}
二分图匹配
算法介绍
最大匹配数:最大匹配的匹配边的数目
最小点覆盖数:选取最少的点,使任意一条边至少有一个端点被选择
最大独立数:选取最多的点,使任意所选两点均不相连
最小路径覆盖数:对于一个 DAG(有向无环图),选取最少条路径,使得每个顶点属于且仅属于一条路径。路径长可以为 0(即单个点)。
定理1:最大匹配数 = 最小点覆盖数(这是 Konig 定理)
定理2:最大匹配数 = 最大独立数
定理3:最小路径覆盖数 = 顶点数 - 最大匹配数
匈牙利算法求解二分图匹配问题
int match[2000];int vis[2000];vector<int >mmp[2000];int find(int u){ for(int i=0;i<mmp[u].size();i++){ int v=mmp[u][i]; if(vis[v]==0){ vis[v]=1; if(match[v]==-1||find(match[v])){ match[v]=u; return 1; } } } return 0;}void init(){ memset(match,-1,sizeof(match)); for(int i=1;i<=n;i++) mmp[i].clear();}void add(int u,int v){ mmp[u].push_back(v); //mmp[v].push_back(u); //无向图才需要}int maxMATCH(){ int ans = 0; //ans 是最大匹配数, for(int i=1;i<=n;i++){ memset(vis,0,sizeof(vis)); if(find(i)) ans++; } //ans/=2; //对于无向图的话 需要ans/=2; return ans ;}bool perfectMATCH(){ if(maxMATCH()==n) return true; else return false;}
2-SAT
强连通分支及其应用(2-SAT)总结
2-SAT
强联通分量一个很重要的用途就是解布尔方程可满足性问题(SAT)。需要学习这一部分知识我们需要一点布尔代数的知识。
下文中我们约定(^表示交v表示并)
例如:(a v b v …)^(c v d v …)^…
这样的我们叫做合取范式。其中(a v b v …)这样的叫做子句。类似a,b…叫做文字。
我们把合取范式中一个子句中包含文字不超过两个的问题成为2-SAT问题。在SAT问题中只有这一类我们可以用线性时间内得出答案。
最常规的2-SAT题目分为大致两种,一种是让你判断有没有解,另一种是让你输出一组解。针对这两种给出模版。
在这之前先来介绍一下2-SAT题目的大致解题步骤:
对于2-SAT问题我们需要构建一张有向图每个文字拆为两个节点 例如 a 变为 a, !a
首先我们从题目中总结出来的都是一些比较杂乱的逻辑表达式,不过一般都是两两之间的关系,我们需要做的第一步是化简成用^连接。然后对于每个子句建边。
建边的规则是这样的 a -> b那么在有向图中建一条a到b的边
我们可能得到的子句有:
a v b 我们可以化简 !a->b ^ !b->a
a -> b 直接连边
a 转化为!a -> a
其中每个文字及其的非对应相应的结点,若是出现在文字前有非的关系例如 !a v b 那么变通一下 就化成 a -> b ^ !b -> !a就可以了。
到这里我们要做的事(建图)就完成了,接下来交给模版,我们来看一下模版做了什么:
首先我们对建完的有向图求强连通分支,若是出现有一个逻辑变量和他的反在同一个联通分之内就无解,否则有解。
若a所在的强连通分支的拓扑序在!a之后a为真,否则为反。怎么样很简单吧。
vector<int> G[N];vector<int> G2[N];vector<int> S;int vis[N] ; //标记数组int sccno[N]; //记录数组 sccno[i] 记录 i属于哪个联通分支int scc_cnt; int n;void dfs1(int u){ if(vis[u]) return ; vis[u] = true; for(int i = 0; i < G[u].size(); i++){ dfs1(G[u][i]); } S.push_back(u);}void dfs2(int u){ if(sccno[u]) return; sccno[u] = scc_cnt; for(int i = 0; i < G2[u].size(); i++){ dfs2(G2[u][i]); }}void find_scc(int n){ scc_cnt = 0; S.clear(); memset(vis , 0 , sizeof(vis)); memset(sccno , 0 , sizeof(sccno)); for(int i = 0; i < n; i++) dfs1(i); for(int i = n - 1; i >= 0; i--) if(!sccno[S[i]]){ scc_cnt++; dfs2(S[i]); }}void AddEdge(int u , int v) { G[u].push_back(v); G2[v].push_back(u);}int main(){ /*** 输入数据 */ /*** 加边 边未两者不能匹配的 example : {u,v} 当选择u的时候一定不能选择v ,需要选择v'; */ find_scc(2 * n); //注意x2 for(int i = 0; i < n; i++){ if(sccno[i] == sccno[i + n]){ //如果有x与x'同时被取或者未取,则匹配失败 puts("NO"); return 0; } } puts("YES"); for(int i = 0; i < n; i++){ if(sccno[i] > sccno[i + n]){ //相关 i; } else { //相关 i'; } } return 0;}/********************************************************//**************************************** 2-SAT kosaraju算法 By 小豪 *****************************************/const int LEN = 200000+10;vector<int> Map[LEN], rMap[LEN], vs;int n, m, vis[LEN], sccn[LEN];void dfs(int v){ vis[v] = 1; for(int i=0; i<Map[v].size(); i++) if(!vis[Map[v][i]]) dfs(Map[v][i]); vs.PB(v);}void rdfs(int v, int f){ vis[v] = 1; sccn[v] = f; for(int i=0; i<rMap[v].size(); i++) if(!vis[rMap[v][i]]) rdfs(rMap[v][i], f);}int scc(){ memset(vis, 0, sizeof vis); vs.clear(); for(int i=0; i<2*n; i++) if(!vis[i]) dfs(i); memset(vis, 0, sizeof vis); int k = 0; for(int i = vs.size()-1; i>=0; i--) if(!vis[vs[i]]) rdfs(vs[i], k++); return k;}void addedge(int a, int b){ Map[a].PB(b); rMap[b].PB(a);}void solve(){ scc(); for(int i=0; i<2*n; i+=2) if(sccn[i] == sccn[i+1]){ //printf("No solution.\n"); //无解 return ; } for(int i=0; i<n; i++){ if(sccn[i*2] > sccn[i*2+1]) printf("Yes\n"); else printf("No\n"); }}
- 图论 [未完成 待续~待修改]
- 数据结构 [未完成 待续~待修改]
- Ajax 待续 未完成
- Objective-C 中的BOOL ---未完成待续
- MODBUS通信协议精析(未完成待续)
- 待修改
- 待修改
- ----------待修改-----------
- 待修改
- android应用之测试利器--StrictMode(未完成,待续)
- Android的自动化构建(一)未完成,待续
- 待修改1
- Spring IOC(待修改)
- InstantMessager待修改部分
- UVA 10815(待修改)
- 后缀表达式《待修改》
- 待修改P124.41
- 获取头像待修改
- php类面向对象学习笔记
- Growth of a Population
- 在慕课上学习的,HTML和CSS基础学习笔记6
- javascript 学习1
- 41、检查重复字符串
- 图论 [未完成 待续~待修改]
- 开源框架(android)
- C++调用Python浅析
- javascript的函数
- ubuntu 16.04 启用root用户方法
- cocos2dx
- linux mint 下如何制作win7启动盘
- bzoj2687 交与并
- Linux下不能进入windows的NTFS分区之挂载错误问题