二分图匹配相关

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


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

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

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

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

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


就光贴一下模板了

#define N 202
int useif[N];   //记录y中节点是否使用 0表示没有访问过,1为访问过
int link[N];   //记录当前与y节点相连的x的节点
int mat[N][N]; //记录连接x和y的边,如果i和j之间有边则为1,否则为0
int 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值