• 最大权二分匹配


    图论里有一个非常经典的算法,那就是二分匹配,只是仅仅是简单的匹配有时并不能解决我们的问题,比方匹配带权的情况。引申的一个非常重要的问题就是分配问题,比方给n个人分派m个任务,每一个人都有不同的成本,怎样分配能使得成本最小就是这种问题,这种问题我们统称为二分图的最大权匹配问题.

    解决这类问题的最好的方法应该就是KM 算法。详细细节能够自己百度!

    以下是我的代码,我主要还是用了类来写,认为这样比較好理解!


    #include<iostream>
    #include<cstdio>
    #include<vector>
    using namespace std;
    #define INF 99999999
    class graph{
      struct vertex
      {
    	 bool vist;              //是否被訪问过
         int link;              //顶标
         int ver;               //匹配边
    	 vector<int>edge;      //相关边
    	 vertex(bool f=0,int v=0,int l=-INF):vist(f),ver(v),link(l){}
      };
      int n,m;
      vector<vertex>V;
      vector<vertex>U;
      vector<int>slack;
      public:
    	  graph(int x,int y):n(x),m(y)
    	  {
    		  vertex tmp;
    		  int i=0;
    		  for(;i<=n;i++)
    		  V.push_back(tmp),
    		  V[i].edge.push_back(0);
    		  for(i=0;i<=m;i++)
    			  U.push_back(tmp),
    			  slack.push_back(INF);
    	  }
    	  void merge(int i,int w)
    	  {
    		  V[i].edge.push_back(w);
    		  V[i].link=V[i].link>w?V[i].link:w;
    	  }
          bool DFS(int x)
    	  {
    		  V[x].vist=1;
    		  for(int y=1;y<=m;y++)
    		  {
                 if(U[y].vist)
    				 continue;
    			 int tmp=V[x].link+U[y].link-V[x].edge[y];
    			 if(tmp==0)
    			 {
    				 U[y].vist=1;
    				 if(U[y].ver==0||DFS(U[y].ver))
    				 {
    					 U[y].ver=x;
    					 V[x].ver=y;
    					 return 1;
    				 }
    			 }
    			 else if(slack[y]>tmp)
    				 slack[y]=tmp;
    		  }
    		  return 0;
    	  }
        int KM()
    	{
    		for(int x=1;x<=n;x++)
    		{
    		   for(int i=1;i<=m;i++)
    		    slack[i]=INF;
             while(1)
    		 {
    		   for(int i=1;i<=n;i++)
    		    V[i].vist=0;
    		    for(int i=1;i<=m;i++)
    		    U[i].vist=0;
    		   if(DFS(x))
                   break;
                 int d=INF ;
                for(int i=1;i<=m;i++)
    				if(!U[i].vist&&d>slack[i])
    					d=slack[i];
    			for(int j=1;j<=n;j++)
    				if(V[j].vist)
    					V[j].link-=d;
    			for(int k=1;k<=m;k++)
    				if(U[k].vist)
    					U[k].link+=d;
    				else
    					slack[k]-=d;
    		 }
           }
        	int MAX=0;
        	for(int i=1;i<=m;i++)
    	    {
    	       if(V[i].ver>0)
                MAX+=V[U[i].ver].edge[i];
    
            }
    		return MAX;
    	}
    
      };
    
    int main()
    {
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    	int n,m;
    	while(cin>>n>>m)
    	{
    	  graph G(n,n);
    	  int w;
    	  for(int i=1;i<=n;i++)
    		  for(int j=1;j<=n;j++)
    			 scanf("%d",&w),
    			 G.merge(i,-w);
    	  int max=-G.KM();
              cout<<max<<endl;
    	
    
    	}
    	  //  fclose(stdin);
    	//    fclose(stdout);
    	return 0;
    }
    
    
    
    
    这个算法的效率是O(n^3)的,这应该是眼下最好的算法了吧。

  • 相关阅读:
    配置数据同步
    NET移动设备开发
    计算两个日期之间的工作日数
    ActionScript3.0程序开发工具
    常用JS积累之获取节点高度(基于浏览器)
    推荐40个优秀的免费CSS工具
    #include语法
    CSS3属性boxshadow使用教程
    CSS元素背景透明
    js获取网页高度
  • 原文地址:https://www.cnblogs.com/yfceshi/p/7258295.html
Copyright © 2020-2023  润新知