最近学习了二分图匹配,在没人指导下自学只能自己一点点摸索
具体是什么意思就自行百度吧。
一篇好文章 :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]);
}
}
}
}