从前一个和谐的班级,有 nlnl 个是男生,有 nrnr 个是女生。编号分别为 1,…,nl1,…,nl 和 1,…,nr1,…,nr。

有若干个这样的条件:第 vv 个男生和第 uu 个女生愿意结为配偶,且结为配偶后幸福程度为 ww。

请问这个班级里幸福程度之和最大是多少?

输入格式

第一行三个正整数,nl,nr,mnl,nr,m。

接下来 mm 行,每行三个整数 v,u,wv,u,w 表示第 vv 个男生和第 uu 个女生愿意结为配偶,且幸福程度为 ww。保证 1≤v≤nl1≤v≤nl,1≤u≤nr1≤u≤nr,保证同一对 v,uv,u 不会出现两次。

输出格式

第一行一个整数,表示幸福程度之和的最大值。

接下来一行 nlnl 个整数,描述一组最优方案。第 vv 个整数表示 vv 号男生的配偶的编号。如果 vv 号男生没配偶请输出 00。

样例一

input

2 2 3
1 1 100
1 2 1
2 1 1

output

100
1 0

限制与约定

1≤nl,nr≤4001≤nl,nr≤400,1≤m≤1600001≤m≤160000,1≤w≤1091≤w≤109。

时间限制:1s1s

空间限制:256MB

二分图最大权匹配模板题 KM算法

KM算法略神奇的样子……

http://www.cnblogs.com/wenruo/p/5264235.html

↑感觉这里讲得挺清晰

KM算法求的是最大权完备匹配,为了解决两边点数不同的情况,需要虚拟一些点使得两边点数相等

↑但是这种DFS写法被无情卡掉

 /*by SilverN*/
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#define LL long long
using namespace std;
const LL INF=1LL<<;
const int mxn=;
int read(){
int x=,f=;char ch=getchar();
while(ch<'' || ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>='' && ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
void write(LL x){
if(x>)write(x/);
putchar(x%+'');
return;
}
inline LL mini(LL a,LL b){return a<b?a:b;}
inline LL maxi(LL a,LL b){return a>b?a:b;}
int nL,nR,bl,br,m;
int visL[mxn],visR[mxn];
LL exL[mxn],exR[mxn];
int link[mxn];
LL slack[mxn];
int mp[mxn][mxn];
LL ans=;
int a[mxn];
int dtime=;
bool DFS(int u){
visL[u]=dtime;
for(int i=;i<=nR;i++){
if(visR[i]==dtime)continue;
LL d=exL[u]+exR[i]-mp[u][i];
if(!d){
visR[i]=dtime;
if(!link[i] || DFS(link[i])){
link[i]=u;
return ;
}
}
else slack[i]=min(slack[i],d);
}
return ;
}
void KM(){
// memset(link,0,sizeof link);
// memset(exR,0,sizeof exR);
for(int i=;i<=nL;i++){
exL[i]=;
for(int j=;j<=nR;j++){
exL[i]=maxi(exL[i],mp[i][j]);
}
}
for(int i=;i<=nL;i++){
// memset(slack,0x3f,sizeof slack);
for(int j=;j<=nR;j++)slack[j]=INF;
while(){//直到匹配成功为止
dtime++;
// memset(visL,0,sizeof visL);
// memset(visR,0,sizeof visR);
if(DFS(i))break;
LL d=INF;
for(int j=;j<=nR;j++){
if(visR[j]!=dtime)d=mini(d,slack[j]);
}
for(int j=;j<=nL;j++){
if(visL[j]==dtime)exL[j]-=d;
if(visR[j]==dtime)exR[j]+=d;
else slack[j]-=d;
}
}
}
ans=;
nL=bl;nR=br;
for(int i=;i<=nR;i++){
if(mp[link[i]][i]){
a[link[i]]=i;
ans+=mp[link[i]][i];
}
}
printf("%lld\n",ans);
for(int i=;i<=nL;i++){
write(a[i]);
putchar(' ');
}
printf("\n");
return;
}
int main(){
int i,j;
nL=read();
nR=read();
bl=nL;br=nR;
nL=max(nL,nR);
nR=nL;
m=read();
int u,v,w;
for(i=;i<=m;i++){
u=read();v=read();w=read();
mp[u][v]=w;
}
KM();
return ;
}

DFS TLE

于是在status里抄了个BFS的写法。

 /*by SilverN*/
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#define LL long long
using namespace std;
const int INF=0x3f3f3f3f;
const int mxn=;
int read(){
int x=,f=;char ch=getchar();
while(ch<'' || ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>='' && ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
void write(LL x){
if(x>)write(x/);
putchar(x%+'');
return;
}
inline int mini(int a,int b){return a<b?a:b;}
inline int maxi(int a,int b){return a>b?a:b;}
int nL,nR,bl,br,m;
int visL[mxn],visR[mxn];
int exL[mxn],exR[mxn];
int link[mxn],pre[mxn],lx[mxn];
int slack[mxn];
int mp[mxn][mxn];
//
LL ans=;
int a[mxn];
int dtime=;
int q[mxn<<],hd,tl;
void Aug(int rt){
if(!rt)return;
link[rt]=pre[rt];
Aug(lx[pre[rt]]);
lx[pre[rt]]=rt;
return;
}
void BFS(int S){
int i,j,tmp;++dtime;
memset(slack,0x3f,sizeof slack);
hd=tl=;q[tl]=S;
while(){
while(hd<=tl){
int u=q[hd];++hd;
visL[u]=dtime;
for(int i=;i<=nR;i++){
if(visR[i]^dtime){
tmp=exL[u]+exR[i]-mp[u][i];
if(!tmp){
visR[i]=dtime;pre[i]=u;
if(!link[i]){
Aug(i);
return;
}
q[++tl]=link[i];
//
}
else if(tmp<slack[i])slack[i]=tmp,pre[i]=u;
}
}
}
tmp=INF;
for(i=;i<=nR;i++)if(visR[i]^dtime)tmp=mini(tmp,slack[i]);
for(i=;i<=nL;i++){
if(visL[i]==dtime)exL[i]-=tmp;
if(visR[i]==dtime)exR[i]+=tmp;
else slack[i]-=tmp;
}
for(i=;i<=nR;i++){
if(visR[i]^dtime && !slack[i]){
visR[i]=dtime;
if(!link[i]){
// link[i]=pre[i];
Aug(i);
return;
}
q[++tl]=link[i];
}
}
}
return;
}
void KM(){
for(int i=;i<=nL;i++){
exL[i]=;
for(int j=;j<=nR;j++)
exL[i]=max(exL[i],mp[i][j]);
}
for(int i=;i<=nL;i++) BFS(i);
ans=;
nL=bl;nR=br;
for(int i=;i<=nR;i++){
if(mp[link[i]][i]){
a[link[i]]=i;
ans+=mp[link[i]][i];
}
}
printf("%lld\n",ans);
for(int i=;i<=nL;i++){
write(a[i]);
putchar(' ');
}
printf("\n");
return;
}
int main(){
int i,j;
nL=read();
nR=read();
bl=nL;br=nR;
nL=max(nL,nR);
nR=nL;
m=read();
int u,v,w;
for(i=;i<=m;i++){
u=read();v=read();w=read();
mp[u][v]=w;
}
KM();
return ;
}

UOJ#80 二分图最大权匹配 [模板题]的更多相关文章

  1. UOJ#80. 二分图最大权匹配 模板

    #80. 二分图最大权匹配 描述 提交 自定义测试 从前一个和谐的班级,有 nlnl 个是男生,有 nrnr 个是女生.编号分别为 1,…,nl1,…,nl 和 1,…,nr1,…,nr. 有若干个这 ...

  2. uoj#80 二分图最大权匹配

    题意:给定二分图,有边权,求最大边权匹配.边权非负. 解:KM算法求解最大权完备匹配. 完备匹配就是点数少的那一边每个点都有匹配. 为了让完备匹配与最大权匹配等价,我们添加若干条0边使之成为完全二分图 ...

  3. [SDOI2006] 仓库管理员的烦恼 - 二分图最大权匹配

    最小化代价,即最大化"本土"货物的数量 于是就是个二分图最大权匹配裸题 #include <bits/stdc++.h> using namespace std; #d ...

  4. @noi.ac - 507@ 二分图最大权匹配

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 有一天你学了一个能解决二分图最大权匹配的算法,你决定将这个算法应 ...

  5. HDU2255 奔小康赚大钱 —— 二分图最大权匹配 KM算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    ...

  6. [ACM] HDU 2255 奔小康赚大钱 (二分图最大权匹配,KM算法)

    奔小康赚大钱 Problem Description 传说在遥远的地方有一个很富裕的村落,有一天,村长决定进行制度改革:又一次分配房子. 这但是一件大事,关系到人民的住房问题啊. 村里共同拥有n间房间 ...

  7. [SDOI2017] 新生舞会 - 二分图最大权匹配,分数规划,二分答案

    有一个二分图,每个部都有 \(n\) 个点,每条边有两个参数 \(a_e, b_e\),求一种匹配,使得 \(\sum a_i / \sum b_i\) 最大 Solution 显然的分数规划,考虑二 ...

  8. [hdu1533]二分图最大权匹配 || 最小费用最大流

    题意:给一个n*m的地图,'m'表示人,'H'表示房子,求所有人都回到房子所走的距离之和的最小值(距离为曼哈顿距离). 思路:比较明显的二分图最大权匹配模型,将每个人向房子连一条边,边权为曼哈顿距离的 ...

  9. POJ2195 Going Home[费用流|二分图最大权匹配]

    Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 22088   Accepted: 11155 Desc ...

随机推荐

  1. Ubuntu下使用Git_1

    这里小小的记录一下我在Ubuntu下使用版本控制工具Git的过程.在学习使用Git的时候,我发现了一个很好的网站,这里分享一下,大家共同学习. 猴子都能懂的Git入门 http://git.wiki. ...

  2. 常见bug解析-移动端

    手机测试常见bug解析 1.测试时遇到“手机无响应”? 有以下几个原因: a.手机内存不足 b.android进程之间死锁引起的(就是两个进程之间) c.手机的CPU运行高引起的 可以查看手机的崩溃日 ...

  3. LeetCode 4——两个排序数组中的中位数

    1. 题目 2. 解答 2.1. 方法一 由于两个数组都是排好序的,因此首先可以想到的思路就是利用归并排序把两个数组合并成一个有序的长数组,然后直接取出中位数即可. class Solution: d ...

  4. js日期插件bootstrap-datetimepicker的使用

    js日期插件——bootstrap-datetimepicker的使用心得: 在大多说的web项目中,都有日期选择器的使用.如果自己写一个日期选择器的话,费时又费力,而且不一定能写出来_(:3 」∠) ...

  5. multi-tap

    multi-tap又称 multi-press . 是在手机,或者电视遥控上的keypad定义,有如下2类标准: 1. ITU-T E.161 2.T9 使用举例如下: Consider a typi ...

  6. libevent显式调用事件处理

    ) { SearchAcceptListen2(p_ev_arg->listen_fd,,&notify_event,base); event_base_loop(base, EVLOO ...

  7. IDEA无法新建GUI Form文件

    因为最近想开发一个IDEA的插件,所以在开发的过程中就需要创建Swing GUI Form文件.但是在项目中右键New中始终就是没有“GUI Form”这个选项,然后自己琢磨寻思着是不是没有启用Swi ...

  8. Linux 监测系统资源

    Top;1; Linux监控磁盘性能 yum install sysstat iostat -x 1 %util:磁盘使用io所占百分比

  9. php 文件上传失败

    使用OSX系统,在使用MAMP Pro作为虚拟服务器,并使用PHP作为后端语言进行文件上传,从临时文件夹拷贝文件的方法为 move_uploaded_file 代码如下: if($_FILES['fi ...

  10. Delphi 检查文件是否存在

    Delphi下检查文件是否存在,我们可以使用FileExists函数 其原形如下: Function FileExists(const FileName: string): Boolean; 示例: ...