您的位置:首页 > 其它

【TJOI2014】匹配(match)

2017-03-29 22:09 267 查看

Description



Solution

这道题目是比较裸的完备匹配的最大权值和,用KM算法(戳这里)轻松解决。对于求交集,明显可以通过删除完备匹配中的一条边,然后再跑一次KM,若是答案减小了,就说明只是一条必须使用的边。

Code

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
#define fo(i,a,b) for(i=a;i<=b;i++)
const int N=100,INF=0x7fffffff;
int a

,eg
,eb
,dis
,match
,c
;
bool visg
,visb
;
int n,i,j,ans,tot,num;
int dfs(int x){
int i,j,tot;
visb[x]=true;
fo(i,1,n){
if(visg[i]) continue;
tot=eb[x]+eg[i];
if(tot==a[x][i]){
visg[i]=true;
if((!match[i])||(dfs(match[i]))){
match[i]=x;
return true;
}
}
else{
dis[i]=min(dis[i],tot-a[x][i]);
}
}
return false;
}
int KM(){
int i,j,tot;
memset(eb,0,sizeof(eb));
memset(eg,0,sizeof(eg));
memset(match,0,sizeof(match));
fo(i,1,n) fo(j,1,n) eb[i]=max(eb[i],a[i][j]);
fo(i,1,n){
memset(dis,127,sizeof(dis));
while(true){
memset(visb,0,sizeof(visb));
memset(visg,0,sizeof(visg));
if(dfs(i)) break;
tot=INF;
fo(j,1,n) if(!visg[j]) tot=min(tot,dis[j]);
fo(j,1,n){
if(visb[j]) eb[j]-=tot;
if(visg[j]) eg[j]+=tot;
else dis[j]-=tot;
}
}
}
tot=0;
fo(i,1,n) tot+=a[match[i]][i];
return tot;
}
int main(){
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);

scanf("%d",&n);
fo(i,1,n) fo(j,1,n) scanf("%d",&a[i][j]);
ans=KM();
printf("%d\n",ans);
fo(i,1,n) c[match[i]]=i;
fo(i,1,n){
num=a[i][c[i]],a[i][c[i]]=0;
tot=KM();
a[i][c[i]]=num;
if(tot<ans) printf("%d %d\n",i,c[i]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息