图论算法Word格式.docx
- 文档编号:20784191
- 上传时间:2023-01-25
- 格式:DOCX
- 页数:18
- 大小:19.61KB
图论算法Word格式.docx
《图论算法Word格式.docx》由会员分享,可在线阅读,更多相关《图论算法Word格式.docx(18页珍藏版)》请在冰豆网上搜索。
=IFN&
dis[j]>
dis[k]+map[k][j])
dis[j]=dis[k]+map[k][j];
}}
intc[maxn][maxn];
intcost[maxn];
intn,m;
voiddijkstra(ints,intend)
cost[i]=c[s][i];
cost[s]=0;
cost[j]=cost[k]+c[k][j];
elseif(!
dis[j]==dis[k]+map[k][j]&
cost[j]>
cost[k]+c[k][j])
printf("
%d%d\n"
dis[end],cost[end]);
2.Floyd-Warshall
1)适用范围:
a)APSP(AllPairsShortestPaths)
b)稠密图效果最佳
c)边权可正可负
intFloyd()
for(k=1;
k<
k++)
if(p[j][k]<
p[j][i]*p[i][k])p[j][k]=p[j][i]*p[i][k];
intflag=1;
if(p[i][i]>
1.0){flag=0;
return1;
}
if(flag)return0;
最大流算法:
Dinic算法:
#defineINF0x1f1f1f1f
#defineMIN(a,b)((a)<
(b)?
(a):
(b))
#defineMAX(a,b)((a)>
#defineN500
intcap[N][N];
//容量
intflow[N][N];
//流量
intlev[N];
//层次
boolvis[N];
//标记
intque[100000];
//队列
//BSF找层次网络,一次寻找多条增广路径
//st最小顶点标号,ed最大顶点标号,src源点标号,tar汇点标号
boolbfs(intst,inted,intsrc,inttar)//st最小点ed最大点src源点tar汇点
{
intfront;
//队首
intrear;
//队尾
front=rear=0;
que[front++]=src;
lev[src]=0;
memset(vis,0,sizeof(vis));
vis[src]=1;
while(rear<
front)
intt=que[rear];
rear++;
for(inti=st;
=ed;
i++)
if(!
vis[i]&
cap[t][i]>
flow[t][i])
vis[i]=1;
lev[i]=lev[t]+1;
que[front++]=i;
}
returnlev[tar]<
INF;
//利用层次网络进行增广,每次DFS寻找的是从该节点出发进行DFS增加的总流量
//mn表示从源点至该节点可增广流量
intdfs(intv,intst,inted,inttar,intfl)//fl表示源点到当前顶点的流量
intret=0;
if(v==tar||fl==0)returnfl;
if(fl==0)break;
if(cap[v][i]>
flow[v][i]&
lev[v]+1==lev[i])
intf=MIN(fl,cap[v][i]-flow[v][i]);
//沿i点向下可用最大流量
inttt=dfs(i,st,ed,tar,f);
//沿i点向下实际增广的流量
if(tt<
=0)continue;
ret+=tt;
fl-=tt;
//每次修改fl
flow[v][i]+=tt;
flow[i][v]-=tt;
returnret;
intdinic(intst,inted,intsrc,inttar)
while(bfs(st,ed,src,tar))//存在可增广路
intr=dfs(src,st,ed,tar,INF);
if(r==0)break;
ret+=r;
-49-
3.11最小费用最大流编写:
程宪庆校核:
周洲
3.11.1基本原理
最小费用最大流问题是在普通的最大流问题上加了另一个条件,即要每条边单位流量所需的费用,要在求得最大流的情况下所需费用最小。
求最小费用可以转化成求解一个最短路问题,而求最大流需要广度搜索,所以可以使用SPFA最短路算法和EK最大流算法结合的方法求解最小费用最大流问题。
3.11.2模板代码
#defineINF0x3f3f3f3f
intmat[55][55];
intn,k;
inthead[5005];
structArc
intnext_arc;
intpoint;
intadj;
intcost;
intcap;
};
structArcarc[25000];
intpre[5005];
intdis[5005];
boolfl[5005];
intmax_flow;
intmin_cost;
intedge_cnt;
voidadd(intu,intv,intcst,intcp)
arc[edge_cnt].next_arc=head[u];
arc[edge_cnt].point=v;
arc[edge_cnt].adj=u;
arc[edge_cnt].cost=cst;
arc[edge_cnt].cap=cp;
head[u]=edge_cnt;
voidcost_flow(intsrc,inttar)
while
(1)
memset(pre,-1,sizeof(pre));
memset(dis,0x3f,sizeof(dis));
memset(fl,0,sizeof(fl));
queue<
int>
q;
q.push(src);
dis[src]=0;
while(!
q.empty())
intu=q.front();
q.pop();
fl[u]=0;
for(inte=head[u];
e!
=-1;
e=arc[e].next_arc)
if(arc[e].cap>
0&
dis[u]+arc[e].cost<
dis[arc[e].point])
dis[arc[e].point]=dis[u]+arc[e].cost;
pre[arc[e].point]=e;
fl[arc[e].point])
fl[arc[e].point]=1;
q.push(arc[e].point);
if(pre[tar]==-1)break;
intmin=INF;
for(inti=tar;
pre[i]!
i=arc[pre[i]].adj)
min=MIN(min,arc[pre[i]].cap);
arc[pre[i]].cap-=min;
arc[pre[i]^1].cap+=min;
max_flow+=min;
min_cost+=min*dis[tar];
2.树的最小支配集,最小点覆盖与最大独立集
深度优先遍历,得到深度优先遍历序列。
intp[maxn];
boolselect[maxn];
intnewpos[maxn];
intnow;
intn,m;
voidDFS(intx)
newpos[now++]=x;
intk;
for(k=head[x];
k!
k=edge[k].next)
if(!
select[edge[k].to])
select[edge[k].to]=true;
p[edge[k].to]=x;
DFS(edge[k].to);
对于最小支配集,贪心函数如下:
intgreedy()
bools[maxn]={0};
boolset[maxn]={0};
intans=0;
inti;
for(i=n-1;
i>
=0;
i--)
intt=newpos[i];
s[t])
set[p[t]])
set[p[t]]=true;
ans++;
s[t]=true;
s[p[t]]=true;
s[p[p[t]]]=true;
returnans;
对于最小点覆盖,贪心函数如下:
=1;
s[t]&
!
s[p[t]])
对于最大独立集,贪心函数如下:
set[t]=true;
使用样例:
intmain()
/*读入图信息*/
memset(select,0,sizeof(select));
now=0;
select[1]=true;
p[1]=1;
DFS
(1);
%d\n"
greedy());
该方法经过一次深度优先遍历和一次贪心得到最终解,第一步的时间复杂度是
O(m),由于这是一棵树,m=n-1。
第二步是O(n),一共是O(n)。
在下面的代码中,u表示当前正在处理的节点,p表示u节点的父节点。
对于最小支配集,动态规函数如下:
voidDP(intu,intp)
dp[u][2]=0;
dp[u][0]=1;
bools=false;
intsum=0,inc=INF;
for(k=head[u];
intto=edge[k].to;
if(to==p)
continue;
DP(to,u);
dp[u][0]+=min(dp[to][0],min(dp[0][1],dp[to][2]));
if(dp[to][0]<
=dp[to][1])
sum+=dp[to][0];
s=true;
else
sum+=dp[to][1];
inc=min(inc,dp[to][0]-dp[to][1]);
if(dp[to][1]!
=INF&
dp[u][2]!
=INF)
dp[u][2]+=dp[to][1];
elsedp[u][2]=INF;
if(inc==INF&
s)
dp[u][1]=INF;
dp[u][1]=sum;
dp[u][1]+=inc;
对于最小点覆盖,动态规划函数如下:
voidDP()
dp[u][1]=0;
intk,to;
to=edge[k].to;
DP(to,u);
dp[u][0]+=min(dp[to][0],dp[to][1]);
dp[u][1]+=dp[to][0];
对于最大独立集,动态规划函数如下:
dp[u][0]+=dp[to][1];
dp[u][1]+=max(dp[to][0],dp[to][1]);
二分图最大匹配
模板代码
#include<
iostream>
string.h>
usingnamespacestd;
//n矩阵规格,k星体数量
intV1,V2;
//二分图顶点集
/*矩阵的行列分别属于二分图的两个顶点集V1、V2,其中行x∈V1,列y∈V2*/
boolgrid[501][501];
//存储数据方式:
可达矩阵
boolvis[501];
//记录V2的点每个点是否已被搜索过
intlink[501];
//记录V2中的点y在V1中所匹配的点x的编号
intm;
//最大匹配数
booldfs(intx)
for(inty=1;
y<
=V2;
y++)
if(grid[x][y]&
vis[y])//x到y相邻(有边)且节点y未被搜索
vis[y]=true;
//标记节点y已被搜索
if(link[y]==0||dfs(link[y]))//link[y]==0:
如果y不属于前一个匹配M
{//find(link[y]:
如果被y匹配到的节点可以寻找到增广路
link[y]=x;
//那么可以更新匹配M'
(用M替代M'
)
returntrue;
//返回匹配成功的标志
returnfalse;
//继续查找V1下一个x的邻接节点
voidsearch(void)
for(intx=1;
x<
=V1;
x++)
memset(vis,false,sizeof(vis));
//清空上次搜索时的标记
if(dfs(x))//从V1中的节点x开始寻找增广路
m++;
return;
intmain(void)
cin>
>
n>
k;
V1=V2=n;
intx,y;
//坐标(临时变量)
for(inti=1;
=k;
x>
y;
grid[x][y]=true;
//相邻节点标记
search();
cout<
<
m<
endl;
return0;
强连通
voidtarjan(inti)
intj;
DFN[i]=LOW[i]=++Dindex;
instack[i]=true;
Stap[++Stop]=i;
for(edge*e=V[i];
e;
e=e->
next)
j=e->
t;
DFN[j])
tarjan(j);
if(LOW[j]<
LOW[i])
LOW[i]=LOW[j];
elseif(instack[j]&
DFN[j]<
LOW[i]=DFN[j];
if(DFN[i]==LOW[i])
Bcnt++;
do
j=Stap[Stop--];
instack[j]=false;
Belong[j]=Bcnt;
while(j!
=i);
voidsolve()
Stop=Bcnt=Dindex=0;
memset(DFN,0,sizeof(DFN));
for(i=1;
=N;
DFN[i])
tarjan(i);
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法