图论算法.docx

上传人:b****5 文档编号:7660841 上传时间:2023-01-25 格式:DOCX 页数:18 大小:19.61KB
下载 相关 举报
图论算法.docx_第1页
第1页 / 共18页
图论算法.docx_第2页
第2页 / 共18页
图论算法.docx_第3页
第3页 / 共18页
图论算法.docx_第4页
第4页 / 共18页
图论算法.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

图论算法.docx

《图论算法.docx》由会员分享,可在线阅读,更多相关《图论算法.docx(18页珍藏版)》请在冰豆网上搜索。

图论算法.docx

图论算法

1.Dijkstra

1)适用条件&范围:

a)单源最短路径(从源点s到其它所有顶点v);

b)有向图&无向图(无向图可以看作(u,v),(v,u)同属于边集E的有向图)

c)所有边权非负(任取(i,j)∈E都有Wij≥0);

constintmaxn=160;

#defineIFN9999999

intmap[maxn][maxn];

intdis[maxn];

voiddijkstra(ints,intn)

{

inti,j,k;

intmin;

boolp[maxn];

for(i=1;i<=n;i++)

{

p[i]=false;

dis[i]=map[s][i];

}

dis[s]=0;

p[s]=true;

for(i=1;i<=n;i++)

{

min=IFN;

k=0;

for(j=1;j<=n;j++)

{

if(!

p[j]&&dis[j]

{

min=dis[j];

k=j;

}

}

p[k]=true;

for(j=1;j<=n;j++)

{if(!

p[j]&&map[k][j]!

=IFN&&dis[j]>dis[k]+map[k][j])

{

dis[j]=dis[k]+map[k][j];

}

}

}}

intmap[maxn][maxn];

intc[maxn][maxn];

intdis[maxn];

intcost[maxn];

intn,m;

voiddijkstra(ints,intend)

{

inti,j,k;

intmin;

boolp[maxn];

for(i=1;i<=n;i++)

{

p[i]=false;

dis[i]=map[s][i];

cost[i]=c[s][i];

 

}

dis[s]=0;

cost[s]=0;

p[s]=true;

for(i=1;i<=n;i++)

{

min=IFN;

k=0;

for(j=1;j<=n;j++)

{

if(!

p[j]&&dis[j]

{

min=dis[j];

k=j;

}

}

p[k]=true;

for(j=1;j<=n;j++)

{

if(!

p[j]&&map[k][j]!

=IFN&&dis[j]>dis[k]+map[k][j])

{

dis[j]=dis[k]+map[k][j];

cost[j]=cost[k]+c[k][j];

}

elseif(!

p[j]&&map[k][j]!

=IFN&&dis[j]==dis[k]+map[k][j]&&cost[j]>cost[k]+c[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()

{

inti,j,k;

for(i=1;i<=n;i++)

for(j=1;j<=n;j++)

for(k=1;k<=n;k++)

if(p[j][k]

intflag=1;

for(i=1;i<=n;i++)

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)>(b)?

(a):

(b))

#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

{

intt=que[rear];

rear++;

for(inti=st;i<=ed;i++)

{

if(!

vis[i]&&cap[t][i]>flow[t][i])

{

vis[i]=1;

lev[i]=lev[t]+1;

que[front++]=i;

}

}

}

returnlev[tar]

}

//利用层次网络进行增广,每次DFS寻找的是从该节点出发进行DFS增加的总流量

//mn表示从源点至该节点可增广流量

intdfs(intv,intst,inted,inttar,intfl)//fl表示源点到当前顶点的流量

{

intret=0;

if(v==tar||fl==0)returnfl;

for(inti=st;i<=ed;i++)

{

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)

{

intret=0;

while(bfs(st,ed,src,tar))//存在可增广路

{

intr=dfs(src,st,ed,tar,INF);

if(r==0)break;

ret+=r;

}

returnret;

}

-49-

3.11最小费用最大流编写:

程宪庆校核:

周洲

3.11.1基本原理

最小费用最大流问题是在普通的最大流问题上加了另一个条件,即要每条边单位流量所需的费用,要在求得最大流的情况下所需费用最小。

求最小费用可以转化成求解一个最短路问题,而求最大流需要广度搜索,所以可以使用SPFA最短路算法和EK最大流算法结合的方法求解最小费用最大流问题。

3.11.2模板代码

#defineINF0x3f3f3f3f

#defineMIN(a,b)((a)<(b)?

(a):

(b))

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));

queueq;

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[u]+arc[e].cost;

pre[arc[e].point]=e;

if(!

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]!

=-1;i=arc[pre[i]].adj)

{

min=MIN(min,arc[pre[i]].cap);

}

for(inti=tar;pre[i]!

=-1;i=arc[pre[i]].adj)

{

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!

=-1;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];

if(!

s[t])

{

if(!

set[p[t]])

{

set[p[t]]=true;

ans++;

}

s[t]=true;

s[p[t]]=true;

s[p[p[t]]]=true;

}

}

returnans;

}

对于最小点覆盖,贪心函数如下:

intgreedy()

{

bools[maxn]={0};

boolset[maxn]={0};

intans=0;

inti;

for(i=n-1;i>=1;i--)

{

intt=newpos[i];

if(!

s[t]&&!

s[p[t]])

{

set[p[t]]=true;

ans++;

s[t]=true;

s[p[t]]=true;

}

}

returnans;

}

对于最大独立集,贪心函数如下:

intgreedy()

{

bools[maxn]={0};

boolset[maxn]={0};

intans=0;

inti;

for(i=n-1;i>=0;i--)

{

intt=newpos[i];

if(!

s[t])

{

set[t]=true;

ans++;

s[t]=true;

s[p[t]]=true;

}

}

returnans;

}

使用样例:

intmain()

{

/*读入图信息*/

memset(select,0,sizeof(select));

now=0;

select[1]=true;

p[1]=1;

DFS

(1);

printf("%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;

intk;

for(k=head[u];k!

=-1;k=edge[k].next)

{

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;

else

{

dp[u][1]=sum;

if(!

s)

dp[u][1]+=inc;

}

}

对于最小点覆盖,动态规划函数如下:

voidDP()

{

dp[u][0]=1;

dp[u][1]=0;

intk,to;

for(k=head[u];k!

=-1;k=edge[k].next)

{

to=edge[k].to;

if(to==p)

continue;

DP(to,u);

dp[u][0]+=min(dp[to][0],dp[to][1]);

dp[u][1]+=dp[to][0];

}

}

对于最大独立集,动态规划函数如下:

voidDP()

{

dp[u][0]=1;

dp[u][1]=0;

intk,to;

for(k=head[u];k!

=-1;k=edge[k].next)

{

to=edge[k].to;

if(to==p)

continue;

DP(to,u);

dp[u][0]+=dp[to][1];

dp[u][1]+=max(dp[to][0],dp[to][1]);

}

}

 

二分图最大匹配

模板代码

#include

#include

usingnamespacestd;

intn,k;//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;i<=k;i++)

{

cin>>x>>y;

grid[x][y]=true;//相邻节点标记

}

search();

cout<

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;

if(!

DFN[j])

{

tarjan(j);

if(LOW[j]

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()

{

inti;

Stop=Bcnt=Dindex=0;

memset(DFN,0,sizeof(DFN));

for(i=1;i<=N;i++)

if(!

DFN[i])

tarjan(i);

}

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 农林牧渔 > 林学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1