二分图匹配相关

来源:互联网 发布:海贼王886 知乎 编辑:程序博客网 时间:2024/05/22 12:10

最近学习了二分图匹配,在没人指导下自学只能自己一点点摸索大哭


具体是什么意思就自行百度吧。

一篇好文章 :http://www.renfei.org/blog/bipartite-matching.html  讲解的非常详细了就不再多说了。

关键是其中的匈牙利算法:

然后找了一篇很有意思的文章。 先学习二分图匹配相关知识看这个会很轻松。

http://blog.csdn.net/dark_scope/article/details/8880547/


就光贴一下模板了

#define N 202int useif[N];   //记录y中节点是否使用 0表示没有访问过,1为访问过int link[N];   //记录当前与y节点相连的x的节点int mat[N][N]; //记录连接x和y的边,如果i和j之间有边则为1,否则为0int gn,gm;    //二分图中x和y中点的数目int can(int t){    int i;    for(i=1;i<=gm;i++)    {       if(useif[i]==0 && mat[t][i])//相连并且还没有使用过       {           useif[i]=1;           if(link[i]==-1 || can(link[i])) //没有连接过或者可以改变他连接的结点,这里使用递归。   换句话就是 是未匹配点即为增广路所以再交换位置。           {              link[i]=t; // 将 y 中的 i 连接 x 中的 t;              return 1;           }       }    }    return 0;}int MaxMatch(){    int i,num;    num=0;    memset(link,0xff,sizeof(link));    for(i=1;i<=gn;i++)    {      memset(useif,0,sizeof(useif));       if(can(i)) num++;    }    return num;}



暂且只先贴一下二分图匹配的匈牙利算法。 其他东西下次再看。

Uvalie7427 是一道二分图匹配的模板题。关键是建好二分图就可以了。

(训练赛的时候没学过这个 。做完先学了二分图匹配然后看了其他队伍代码,加了注释应该比较清晰了)

#include<iostream>#include<queue>#include<cstdio>#include<string>#include<vector>#include<map>#include<algorithm>#include<cstring>using namespace std;typedef long long  ll;const int maxn = 20000;vector<int> g[maxn+5]; //建表vector<ll> num; //存入+ - *的结果int from[maxn];  //右边某个数指向左边某个数int to[maxn];  //代表左边第i个与右边哪个数匹配bool use[maxn];map<int,ll>tmp;int n;ll a[maxn];//存数ll b[maxn];//存数bool judge(int x){    for(int i=0; i<g[x].size(); i++)    {        if(!use[g[x][i]])        {            use[g[x][i]] = true;            if(from[g[x][i]] == -1 || judge(from[g[x][i]]))            {                from[g[x][i]] = x;                to[x] = g[x][i];                return true;            }        }    }    return false;}int main(){   while(scanf("%d",&n)!=EOF)   {       num.clear();tmp.clear();       for(int i=0; i<n; i++) g[i].clear();       for(int i=0; i<n; i++)       {           scanf("%lld%lld",&a[i],&b[i]);           num.push_back(a[i]+b[i]);           num.push_back(a[i]-b[i]);           num.push_back(a[i]*b[i]);       }       sort(num.begin(),num.end());       int totsum = unique(num.begin(),num.end()) - num.begin();  //这边是+ - *去除的步骤       for(int i=0; i<totsum; i++)       {           tmp[num[i]] = i; //讲结果按1 2 3 4排在二分图右边           //cout << num[i] << "QQQ" << endl;       }       for(int i=0; i<n; i++)       {           g[i].push_back(tmp[a[i]+b[i]]);           g[i].push_back(tmp[a[i]-b[i]]);           g[i].push_back(tmp[a[i]*b[i]]);   //建二分图 即左边第i个对应右边第 x , y ,z三个       }       int tot = 0;       memset(from,-1,sizeof(from));       memset(to,-1,sizeof(to));       for(int i=0; i<n; i++)       {           memset(use,0,sizeof(use)); //从左边第1个开始 匈牙利算法           if(judge(i)) ++tot;       }       if(tot<n)        printf("impossible\n");       else       {           for(int i=0; i<n; i++)           {               int tmp = to[i];  //tmp是右边第某个数                if(a[i]+b[i] == num[tmp])                printf("%lld + %lld = %lld\n",a[i],b[i],a[i]+b[i]);               else if(a[i]-b[i] == num[tmp])                printf("%lld - %lld = %lld\n",a[i],b[i],a[i]-b[i]);               else if(a[i]*b[i] == num[tmp])                printf("%lld * %lld = %lld\n",a[i],b[i],a[i]*b[i]);           }       }   }}


0 0
原创粉丝点击