日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

图论 —— 二分图 —— KM 算法

發布時間:2025/3/17 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 图论 —— 二分图 —— KM 算法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【原理】

KM 算法是用于求帶權二分圖的最優匹配的算法,其時間復雜度為 O(N^3)。

1.首先選擇頂點數較少的為 X 部(左點集),初始時對 X 部的每一個頂點設置頂標,頂標的值為該點關聯的最大邊的權值,Y 部(右點集)的頂點頂標為 0。

2.對于 X 部中的每個頂點,在相等子圖中利用匈牙利算法找一條增廣路徑,如果沒有找到,則修改頂標,擴大相等子圖,繼續找增廣路徑。

3.當 X 部的每個點都找到增廣路徑時,此時意味著每個點都在匹配中,即找到了該二分圖的完全匹配。該完全匹配即為二分圖的最優匹配。

【有關概念】

1)相等子圖:由于每個頂點有一個頂標,如果選擇邊權等于兩端點的頂標之和的邊,它們組成的圖稱為相等子圖。

2)頂標:每個點的頂標為該點關聯的最大邊的權值。

【頂標的修改】

如果從 X 部中的某個點 Xi 出發在相等子圖中沒有找到增廣路徑,則需要修改頂標。

如果沒有找到增廣路徑,則一定找到了許多條從 Xi 出發并結束于 X 部的匹配邊與未匹配邊交替出現的路徑,即交錯路。

將交錯路中 X 部的頂點頂標減去一個值 d,交錯路中屬于 Y 部的頂點頂標加上一個值 d,那么會發現:

  • 兩端都在交錯路中的邊(i,j),其頂標和沒有變化,即:其原屬于相等子圖,現仍屬于相等子圖。
  • 兩端都不在交錯路中的邊(i,j),其頂標也沒有變化,即:其原來屬于(或不屬于)相等子圖,現仍屬于(或不屬于)相等子圖。
  • X 端不在交錯路中,Y 端在交錯路中的邊(i,j),其頂標和會增大,即:其原來不屬于相等子圖,現仍不屬于相等子圖。
  • X 端在交錯路中,Y 端不在交錯路中的邊(i,j),其頂標和會減小,即:其原來不屬于相等子圖,現可能進入相等子圖,從而使相等子圖得到擴大。

修改頂標的目的就是要擴大相等子圖,為保證至少有一條邊進入相等子圖,可以在交錯路的邊中尋找頂標和與邊權之差最小的邊,也即前述的 d 值。

將交錯路中屬于 X 部的頂點減去 d,交錯路中屬于 Y 部的頂點加上 d,則可以保證至少有一條邊擴充進入相等子圖。

【相等子圖的性質】

1)任意時刻,相等子圖的 最大權匹配 ≤ 相等子圖的頂標和

2)任意時刻,相等子圖的 頂標和=所有頂點的頂標和

3)擴充相等子圖后,相等子圖的頂標和會減小

4)相等子圖的 最大匹配=原圖的完全匹配 時,匹配邊的權值和=所有頂點的頂標和,此匹配即為最優匹配

【實現】

1.最優匹配

#include<cstdio> #include<cstring> #include<cmath> #define INF 0x3f3f3f3f #define N 1001 int n,m;//x、y中結點個數,下標從1開始 int G[N][N];//邊權值矩陣 int Lx[N],Ly[N];//x、y中每個點的期望值 bool visX[N],visY[N];//標記左右點集是否已被訪問過 int linkX[N],linkY[N];//linkX[i]表示與X部中點i匹配的點,linkY[i]表示與Y部中點i匹配的點,-1時表示無匹配 bool dfs(int x){visX[x]=true;for(int y=1;y<=m;y++){if(!visY[y]){int temp=Lx[x]+Ly[y]-G[x][y];if(temp==0){//不在交替路中visY[y]=true;//放入交替路if(linkY[y]==-1 || dfs(linkY[y])){//如果是未匹配點,說明交替路是增廣路linkX[x]=y;//交換路徑linkY[y]=x;return true;//返回成功}}}}return false;//不存在增廣路 } void update(){int minn=INF;for(int i=1;i<=n;i++){//找出邊權與頂標和的最小的差值if(visX[i]){for(int j=1;j<=m;j++){if(!visY[j]){minn=min(minn,Lx[i]+Ly[j]-G[i][j]);}}}}for(int j=1;j<=n;j++)//將交錯路中X部的點的頂標減去minnif(visX[j])Lx[j]-=minn;for(int j=1;j<=m;j++)//將交錯路中Y部的點的頂標加上minnif(visY[j])Ly[j]+=minn; } int KM(){//更新理想值,納入更多的邊memset(linkX,-1,sizeof(linkX));memset(linkY,-1,sizeof(linkY));memset(Lx,0,sizeof(Lx));memset(Ly,0,sizeof(Ly));for(int i=1;i<=n;i++)//更新理想值for(int j=1;j<=m;j++)Lx[i]=max(Lx[i],G[i][j]);for(int i=1;i<=n;i++){while(true){memset(visX,false,sizeof(visX));memset(visY,false,sizeof(visY));if(dfs(i))break;elseupdate();}}int ans=0;for(int i=1;i<=n;i++)if(linkY[i]!=-1)//若存在邊ans+=G[linkY[i]][i];//統計邊權和return ans; }int main(){while(scanf("%d%d",&n,&m)!=EOF&&(n+m)){for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&G[i][j]);printf("%d\n",KM());}return 0; }

2.邊權和最小的完全匹配

使用 KM 算法只能求二分圖的最優匹配,即邊權和最大的完全匹配,?這里有一個技巧,就是將所有的邊權取負,再進行 KM 算法,得到的解取負就是邊權和最小的完全匹配

假設存在一個最優解 res,是所有解中花費最小的,那么 -res 自然是所有花費中最大的解,當將所有邊權取負后,用 KM 算法得到的最優匹配必然是那個花費最大的解,取負后就是所需的最小邊權值的解

#include<cstdio> #include<cstring> #include<cmath> #define INF 0x3f3f3f3f #define N 1001 int n,m;//x、y中結點個數,下標從1開始 int G[N][N];//邊權值矩陣 int Lx[N],Ly[N];//x、y中每個點的期望值 bool visX[N],visY[N];//標記左右點集是否已被訪問過 int linkX[N],linkY[N];//linkX[i]表示與X部中點i匹配的點,linkY[i]表示與Y部中點i匹配的點,-1時表示無匹配 bool dfs(int x){visX[x]=true;for(int y=1;y<=m;y++){if(!visY[y]){int temp=Lx[x]+Ly[y]-G[x][y];if(temp==0){//不在交替路中visY[y]=true;//放入交替路if(linkY[y]==-1 || dfs(linkY[y])){//如果是未匹配點,說明交替路是增廣路linkX[x]=y;//交換路徑linkY[y]=x;return true;//返回成功}}}}return false;//不存在增廣路 } void update(){int minn=INF;for(int i=1;i<=n;i++){//找出邊權與頂標和的最小的差值if(visX[i]){for(int j=1;j<=m;j++){if(!visY[j]){minn=min(minn,Lx[i]+Ly[j]-G[i][j]);}}}}for(int j=1;j<=n;j++)//將交錯路中X部的點的頂標減去minnif(visX[j])Lx[j]-=minn;for(int j=1;j<=m;j++)//將交錯路中Y部的點的頂標加上minnif(visY[j])Ly[j]+=minn; } int KM(){//更新理想值,納入更多的邊memset(linkX,-1,sizeof(linkX));memset(linkY,-1,sizeof(linkY));memset(Lx,0,sizeof(Lx));memset(Ly,0,sizeof(Ly));for(int i=1;i<=n;i++)//更新理想值for(int j=1;j<=m;j++)Lx[i]=max(Lx[i],G[i][j]);for(int i=1;i<=n;i++){while(true){memset(visX,false,sizeof(visX));memset(visY,false,sizeof(visY));if(dfs(i))break;elseupdate();}}int ans=0;for(int i=1;i<=n;i++)if(linkY[i]!=-1)ans+=G[linkY[i]][i];return ans; }int main(){while(scanf("%d%d",&n,&m)!=EOF&&(n+m)){for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&G[i][j]);G[i][j]=-G[i][j];printf("%d\n",-KM());}return 0; }

3.最小有向環覆蓋權值和

若原圖能由多個不相交的有向環覆蓋,那么二分圖一定存在完全匹配,比如:原圖中有向環為 1-2-3-1,則二分圖的完全匹配就是 1-2',2-3',3-1'

由于有向環覆蓋對應一個二分圖的完全匹配,該完全匹配的權值對應有向環覆蓋的權值,因此原圖權值最大的有向環匹配就是二分圖最優匹配的值

要求最小權值和,因此將邊的權值全部取負,再進行計算,最后結果再取負即可

#include<cstdio> #include<cstring> #include<cmath> #define INF 0x3f3f3f3f #define N 1001 int n,m; int G[N][N]; int Lx[N],Ly[N]; bool visX[N],visY[N]; int linkX[N],linkY[N]; bool dfs(int x){visX[x]=true;for(int y=1;y<=m;y++){if(!visY[y]){int temp=Lx[x]+Ly[y]-G[x][y];if(temp==0){visY[y]=true;if(linkY[y]==-1 || dfs(linkY[y])){linkX[x]=y;linkY[y]=x;return true;}}}}return false; } void update(){int minn=INF;for(int i=1;i<=n;i++)if(visX[i])for(int j=1;j<=m;j++)if(!visY[j])minn=min(minn,Lx[i]+Ly[j]-G[i][j]);for(int i=1;i<=n;i++)if(visX[i])Lx[i]-=minn;for(int i=1;i<=m;i++)if(visY[i])Ly[i]+=minn; } int KM(){memset(linkX,-1,sizeof(linkX));memset(linkY,-1,sizeof(linkY));for(int i=1;i<=n;i++){Lx[i]=Ly[i]=0;for(int j=1;j<=m;j++)Lx[i]=max(Lx[i],G[i][j]);}for(int i=1;i<=n;i++){while(true){memset(visX,false,sizeof(visX));memset(visY,false,sizeof(visY));if(dfs(i))break;elseupdate();}}int ans=0;for(int i=1;i<=m;i++){if(G[linkY[i]][i]==-INF){return 1;}ans+=G[linkY[i]][i];}return ans; } int main(){while(scanf("%d%d",&n,&m)!=EOF&&(n+m)){for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)G[i][j]=-INF;while(m--){int x,y,w;scanf("%d%d%d",&x,&y,&w);G[x][y]=max(G[x][y],-w);//處理重邊G[y][x]=G[x][y];//無向圖}int res=-KM();if(res==-1)printf("NO\n";elseprintf("%d\n",res);}return 0; }

4.優先用原匹配邊構建的最優匹配

最優匹配可以直接使用 KM 模版,但是要在原匹配邊的基礎上使得改變的邊最少,可以進行如下的處理:

左邊點集有 n?個點,且 n<=m,則最優匹配必有 n 條邊,讓原圖中的每條邊的權值都乘以 (n+1),即擴大 n+1 倍,且若某邊本來就是原匹配用的其中一條邊,那么該邊權值在擴大 n+1 倍后,再加1。

因此任意一條邊的權值只能是 n+1 的倍數(n+1 的倍數)+1,要在這種權值的邊中選出 n 條來,最終得到的最優權值和 ans? 除以 n+1,即為最優匹配解,因此就算是所有邊均使用原先的匹配,也即在所有權值的基礎上加了 n 個 1,此時除以 n+1,減去原匹配的值就是最優匹配比原匹配增長的值

如果在新二分圖中求出的權值和為 n+1 的倍數,則說明最優匹配中一條老邊都沒有復用。

綜上:所有邊權值*(n+1),老邊再 +1,最終?ans%(n+1) 就是復用舊邊的條數,ans/(n+1)-oldVal 就是最優匹配比原匹配增長的值。

#include<cstdio> #include<cstring> #include<cmath> #define INF 0x3f3f3f3f #define N 1001 int n,m; int G[N][N]; int Lx[N],Ly[N]; bool visX[N],visY[N]; int linkX[N],linkY[N]; bool dfs(int x){visX[x]=true;for(int y=1;y<=m;y++){if(!visY[y]){int temp=Lx[x]+Ly[y]-G[x][y];if(temp==0){visY[y]=true;if(linkY[y]==-1 || dfs(linkY[y])){linkX[x]=y;linkY[y]=x;return true;}}}}return false; } void update(){int minn=INF;for(int i=1;i<=n;i++)if(visX[i])for(int j=1;j<=m;j++)if(!visY[j])minn=min(minn,Lx[i]+Ly[j]-G[i][j]);for(int i=1;i<=n;i++)if(visX[i])Lx[i]-=minn;for(int i=1;i<=m;i++)if(visY[i])Ly[i]+=minn; } int KM(){memset(linkX,-1,sizeof(linkX));memset(linkY,-1,sizeof(linkY));for(int i=1;i<=n;i++){Lx[i]=Ly[i]=0;for(int j=1;j<=m;j++)Lx[i]=max(Lx[i],G[i][j]);}for(int i=1;i<=n;i++){while(true){memset(visX,false,sizeof(visX));memset(visY,false,sizeof(visY));if(dfs(i))break;elseupdate();}}int ans=0;for(int i=1;i<=m;i++)if(linkY[i]!=-1)ans+=G[linkY[i]][i];return ans; } int main(){while(scanf("%d%d",&n,&m)!=EOF&&(n+m)){for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){scanf("%d",&G[i][j]);G[i][j]=G[i][j]*(n+1);//每條邊乘以(n+1)}}int oldVal=0;//記錄原匹配權值和for(int i=1;i<=n;i++){int j;scanf("%d",&j);oldVal+=(G[i][j]/(n+1));//累計原匹配權值G[i][j]++;//老邊+1}int ans=KM();int v1=ans/(n+1);//最優匹配的權值和int v2=v1-oldVal;//最優匹配比原匹配相比多的權值數int v3=ans%(n+1);//最優匹配使用的老邊數int v4=n-v3;//最優匹配使用的新邊數printf("%d\n",v1);printf("%d\n",v2);printf("%d\n",v3);printf("%d\n",v4);}return 0; }

?

總結

以上是生活随笔為你收集整理的图论 —— 二分图 —— KM 算法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 高h放荡受浪受bl | 激情九月天| 日日操av | 亚洲七区 | a天堂在线视频 | 神马影院午夜伦理片 | 一区二区三区免费观看视频 | 日韩av大片| 97视频资源 | 日韩欧美国产一区二区 | 国产青青 | 日日摸天天添天天添破 | 少妇3p视频 | 狠狠操狠狠插 | 午夜国产一区二区 | 日本少妇喂奶漫画 | 午夜精彩视频 | 综合精品久久久 | 又黄又爽无遮挡 | 91日韩精品 | 色综合天天综合网天天狠天天 | 精品一区二区av | 麻豆91av| 入禽太深免费视频 | 免费的三级网站 | 亚洲一区二区三区四区五区午夜 | 福利午夜视频 | 36d大奶| 在线欧美a | 青青草社区| 亚洲色图久久 | 奇米影视777四色 | 狠狠撸在线视频 | 欧美日韩国产精品一区二区三区 | 久久免费视频一区二区 | 在线看b| 黑丝一区 | 欧美亚洲日本 | 国产高清在线免费观看 | 丰满岳乱妇国产精品一区 | 亚洲午夜精品久久久久久浪潮 | 理论片av | 欧美精品一区二区三区久久久 | www久久久久 | 91麻豆精品国产理伦片在线观看 | 91av免费| 碧蓝之海动漫在线观看免费高清 | 国产手机在线 | 日韩精品中文字幕一区二区三区 | 亚洲天堂国产精品 | 污污内射久久一区二区欧美日韩 | 成人毛片在线 | 91波多野结衣 | 中文字幕人妻伦伦 | 日韩h视频| 日本高清免费aaaaa大片视频 | 日韩网站在线观看 | 91精品国产综合久久精品图片 | 主播福利在线 | 日韩午夜网站 | 欧美一区二区公司 | 国产有码 | 欧美综合自拍亚洲综合图片区 | 黄色片播放器 | 少妇高潮惨叫久久久久久 | 国产鲁鲁视频在线观看特色 | 啪啪网视频 | 欧美激情另类 | 久热国产精品 | 日本午夜小视频 | 国产福利一区在线观看 | 国产精品精品软件视频 | 日韩欧美国产综合 | 久久99操 | 日韩成人精品在线 | 国产精品4区 | 欧美一级看片 | 欧美一级黄色大片 | 亚洲女女做受ⅹxx高潮 | 亚洲网站色 | 瑟瑟视频免费看 | 美女视频在线免费观看 | 国产精品免费入口 | 久久久久国产精品熟女影院 | 欧美日韩国产免费一区二区三区 | 久久免费黄色网址 | 蜜桃成人网 | 野外吮她的花蒂高h在线观看 | 自拍视频网站 | 国产精品乱码一区二区三区 | 在线婷婷 | 99国产精品99久久久久久 | wwww黄色片| 亚洲国产一二三区 | 香蕉a视频| 超级碰在线视频 | 午夜在线| 丁香婷婷久久久综合精品国产 | 激情一区二区三区 |