Description
Input
Output
Sample Input
3
1 1 1
2 1 1
1 1 1
Sample Output
4
2 1
Data Constraint
对于30%的数据,N<=30
对于100%的数据,N<=80
分析
题目其实就是叫我们求一个带权二分图的所有的最优匹配的交集
那我们就可以先跑一遍费用流,求出一个最优匹配,然后枚举最优匹配的每一条边,将其删除之后 重新求最优匹配,若最优匹配发生变化则说明这条边在交集中。
代码
#include <bits/stdc++.h>
using namespace std;
#define maxm 20005
#define maxn 200
int me[maxn],prev[maxn],pree[maxn],inq[maxn],dis[maxn];
int s,t;
int ma[maxn],maxc1,maxc,n,gc[maxm],gcost[maxm],gv[maxm],gn[maxm],gbro[maxn],nedge;
void addedge(int u,int v,int c,int cost)
{
gc[nedge] = c;
gv[nedge] = v;
gcost[nedge] = cost;
gn[nedge] = gbro[u];
gbro[u] = nedge;
nedge++;
}
void mcf(int a)
{
maxc1 = 0;
queue<int> Q;
while(1)
{
for(int i = 1;i<=t;i++) dis[i] = INT_MAX;
dis[s] = 0;
Q.push(s);
memset(inq,0,sizeof(inq));
inq[s] = 1;
while(!Q.empty())
{
int q = Q.front();
inq[q] = 0;
Q.pop();
for(int i = gbro[q];i!=-1;i = gn[i])
if(gc[i] && dis[gv[i]] > dis[q] + gcost[i] && i != a)
{
prev[gv[i]] = q;
pree[gv[i]] = i;
dis[gv[i]] = dis[q] + gcost[i];
if(!inq[gv[i]])
{
Q.push(gv[i]);
inq[gv[i]] = 1;
}
}
}
if(dis[t] == INT_MAX) break;
maxc1 += dis[t];
int p = t;
while(p != s)
{
gc[pree[p]] = 0;
gc[pree[p]^1] = 1;
p = prev[p];
}
}
}
int main()
{
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
memset(gbro,-1,sizeof(gbro));
scanf("%d",&n);
for(int i = 1;i<=n;i++)
for(int j = 1;j<=n;j++)
{
int t;
scanf("%d",&t);
addedge(i,j+n,1,-t);
addedge(j+n,i,0,t);
}
s = n+n+1;
t = n+n+2;
for(int i = 1;i<=n;i++)
{
addedge(s,i,1,0);
addedge(i,s,0,0);
addedge(n+i,t,1,0);
addedge(t,n+i,0,0);
}
mcf(-1);
maxc = maxc1;
printf("%d\n",-maxc);
for(int i = 1;i<=n;i++)
for(int j = gbro[i];j!=-1;j = gn[j])
if(gc[j] == 0 && gv[j]!= s)
{
ma[i] = gv[j];
me[i] = j;
gc[j] = 1;
gc[j^1] = 0;
break;
}
for(int i = gbro[s];i!=-1;i = gn[i])
gc[i] = 1,gc[i^1] = 0;
for(int i = gbro[t];i!=-1;i = gn[i])
gc[i] = 0,gc[i^1] = 1;
for(int i = 1;i<=n;i++)
{
mcf(me[i]);
if(maxc1 != maxc) printf("%d %d\n",i,ma[i]-n);
for(int i = 1;i<=n;i++)
for(int j = gbro[i];j!=-1;j = gn[j])
if(gc[j] == 0 && gv[j]!= s)
{
gc[j] = 1;
gc[j^1] = 0;
break;
}
for(int i = gbro[s];i!=-1;i = gn[i])
gc[i] = 1,gc[i^1] = 0;
for(int i = gbro[t];i!=-1;i = gn[i])
gc[i] = 0,gc[i^1] = 1;
}
return 0;
}