构图比较裸,只是上下界费用流不好做= =
源点向每个行节点连接下界为1上界为INF费用为0的边,每个列节点向汇点连接下界为1上界为INF费用为0的边,行节点向列节点连接下界为0上界为1费用为该点值的边,求一最小费用可行流就好。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<fstream>
#include<map>
#include<ctime>
#include<set>
#include<queue>
#include<cmath>
#include<vector>
#include<bitset>
#include<functional>
#define x first
#define y second
#define mp make_pair
#define pb push_back
using namespace std;
typedef long long LL;
typedef double ld;
const LL INF=10000000000000LL;
const int MAX=100000+10;
int n,m,S,T;
int s[MAX],t[MAX],a[MAX],C[MAX];
LL in[MAX];
struct Edge
{
int s,t,next;
LL flow,C,cost;
}e[MAX*10];
int begin[MAX],tot;
void addedge(int u,int v,LL C,LL cost)
{
e[tot].s=u;e[tot].t=v;e[tot].next=begin[u];begin[u]=tot;
e[tot].flow=0;e[tot].C=C;e[tot].cost=cost;
tot++;
}
void add(int u,int v,LL C,LL cost)
{
addedge(u,v,C,cost);
addedge(v,u,0,-cost);
}
LL dist[MAX];
int hash[MAX],come[MAX];
int SPFA()
{
queue<int> q;
int i,u,v;
memset(hash,0,sizeof hash);
for(i=0;i<=T;++i)dist[i]=INF;
q.push(S);hash[S]=1;dist[S]=0;come[S]=-1;
while(!q.empty())
{
u=q.front();q.pop();hash[u]=0;
for(i=begin[u];i!=-1;i=e[i].next)
if(e[i].C>e[i].flow)
{
v=e[i].t;
if(dist[v]>dist[u]+e[i].cost)
{
dist[v]=dist[u]+e[i].cost,come[v]=i;
if(!hash[v])
hash[v]=1,q.push(v);
}
}
}
return dist[T]!=INF;
}
int main()
{
int Cas;
scanf("%d",&Cas);
int sum=0;
while(Cas--)
{
sum++;
tot=0;
memset(begin,-1,sizeof (begin));
memset(in,0,sizeof (in));
scanf("%d%d",&n,&m);
int i,j,u;
S=n+m+2,T=n+m+3;
add(n+m+1,0,INF,0);
for(i=1;i<=n;++i)
{
add(0,i,INF-1,0);
in[0]-=1;
in[i]+=1;
}
for(i=1;i<=m;++i)
{
add(i+n,m+n+1,INF-1,0);
in[i+n]-=1;
in[m+n+1]+=1;
}
LL ans=0;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
scanf("%d",&u);
add(i,j+n,INF,u);
}
}
for(i=0;i<=n+m+1;++i)
{
if(in[i]>0)add(S,i,in[i],0);
else add(i,T,-in[i],0);
}
while(SPFA())
{
LL mm=INF;
int u=T;
while(u!=S)
{
mm=min(e[come[u]].C-e[come[u]].flow,mm);
u=e[come[u]].s;
}
ans+=mm*dist[T];
u=T;
while(u!=S)
{
e[come[u]].flow+=mm;
e[come[u]^1].flow-=mm;
u=e[come[u]].s;
}
}
printf("Case %d: %lld\n",sum,ans);
}
return 0;
}