您的位置:首页 > 其它

2018年2月28日训练日记

2018-02-28 21:27 190 查看
昨晚趁着精神好看资料到三点多,中间发现一道水题就交了一发,居然还submit failed。。。二分图最大匹配最优匹配会了之后感觉很简单,最难的地方还是建图。今天醒来又交了一遍WA,找了半天发现这道题可能有重边。。。(已经在重边这里错了若干次了)
E题swap就是一个二分图最大匹配,可是我怎么都过不了样例,郁闷了我两三天,后来才发现输出任意答案都行,而且根据矩阵性质,如果行交换不能达到条件的话,列交换或行列交换也不可能达到条件。并且它这个交换还是一步交换,即某两行交换完了就不可以再交换。这道题还是有必要写一下题解的。。。(好不容易整出思路,一个小细节错了又害我找了半天)
今天看一般图匹配带花树和二分图多重匹配
貌似二分图多重匹配可以用网络流做。。。赶紧去复习了一下网络流
感觉网络流还是写起来比较麻烦。。。而且为了熟悉二分图多重匹配,就不用网络流做了,以后用网络流再做一遍
先学习完网络流以后,建图就比较好想了。。。于是先去做专题里的题,题目用到二分或floyed也跟网络流里的差不多。。。
专题里三道二分图多重匹配题都用到了二分,也是比较经典的二分,有一道还用到了floyed。
需要注意几点:
1、n和m不能搞混 否则就 WA RE
2、注意初始化 数组及时清零 注意编号 注意是否有重边
3、题意一定要弄清楚,n,m,k都是什么含义,否则我就不说了,都懂
4、用floyed求最短路时一定要把距离0置为inf,因为0会干扰求最短路
5、二分图多重匹配题目用网络流也可以做,不过实现起来比较麻烦,但是两种方式大同小异
贴上poj 2112 Optimal Milking (floyed + 二分图多重匹配/网络流 + 二分)的个人代码:#include<iostream>
#include<cmath>
#include<iomanip>
#include<map>
#include<vector>
#include<algorithm>
#include<queue>
#include<string>
#include<cstdio>
#include<cstring>
#include<set>
using namespace std;
const int maxn=610;
const int maxm=610;
const int inf=1e9;
const int mo=1e9+7;
int n,m,lk[maxn][maxm],ans,k;
int g[maxm][maxn],num[maxm];
int c[maxn][maxm];
bool jd[maxn][maxm],us[maxm];
bool dfs(int u)
{
for(int v=1;v<=n;v++)
if(jd[u][v]&&!us[v])
{
us[v]=1;
if(g[v][0]<k)
{
g[v][++g[v][0]]=u;
return true;
}
for(int i=1;i<=g[v][0];i++)
if(dfs(g[v][i]))
{
g[v][i]=u;
return 1;
}
}
return 0;
}
bool solve(int mid)
{
for(int i=1;i<=n;i++) g[i][0]=0;//注意n m
for(int u=1;u<=m;u++)
{
memset(us,0,sizeof(us));
if(!dfs(u))return 0;
}
return 1;
}
bool jud(int mid)
{
memset(jd,0,sizeof(jd));
for(int i=n+1;i<=n+m;i++)
for(int j=1;j<=n;j++)
{
if(c[i][j]<=mid) jd[i-n][j]=1;//注意编号
}
return solve(mid);
}
int main()
{
char s[20],ch;
int v;
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
//memset(jd,0,sizeof(jd));
int r=inf;
for(int i=1;i<=n+m;i++)
for(int j=1;j<=n+m;j++)
{
scanf("%d",&c[i][j]);
if(!c[i][j]) c[i][j]=inf;//距离为0置为inf
}
for(int kk=1;kk<=n+m;kk++)
for(int i=1;i<=n+m;i++)
for(int j=1;j<=n+m;j++)
if(c[i][kk]+c[kk][j]<c[i][j])c[i][j]=c[i][kk]+c[kk][j];
int l=1;
while(l<=r)//二分
{
int mid=((l+r)>>1);
if(jud(mid)) {r=mid-1;}
else l=mid+1;
}
printf("%d\n",l);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息