思路:这题刚开始一看没太懂,然后想想原来是裸的最大费用最大流,建图后搞下就行了。
不过题目说是用二分匹配来做,因为自己二分匹配的那个带权匹配不会,所以直接用最小费用最大流来做了,反正都一样能求。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<queue> #include<set> #include<cmath> #include<bitset> #define mem(a,b) memset(a,b,sizeof(a)) #define lson i<<1,l,mid #define rson i<<1|1,mid+1,r #define llson j<<1,l,mid #define rrson j<<1|1,mid+1,r #define INF 0x7fffffff typedef long long ll; typedef unsigned long long ull; using namespace std; #define maxn 20005 struct { int v,w,c,next,re; //re记录逆边的下标,c是费用,w是流量 } e[maxn]; int sink,cnt,flow,minflow; int head[maxn],que[maxn*10],pre[maxn],dis[maxn]; bool vis[maxn]; void add(int u, int v, int w, int c) { e[cnt].v=v,e[cnt].w=w,e[cnt].c=c; e[cnt].next=head[u]; e[cnt].re=cnt+1,head[u]=cnt++; e[cnt].v=u,e[cnt].w=0,e[cnt].c=-c; e[cnt].next=head[v]; e[cnt].re=cnt-1,head[v]=cnt++; } bool spfa() { int i, l = 0, r = 1; for(i = 0; i <= sink; i ++) dis[i] = INF,vis[i] = false; dis[0]=0,que[0]=0,minflow=INF,vis[0]=true; while(l<r) { int u=que[l++]; for(i=head[u]; i!=-1; i=e[i].next) { int v = e[i].v; if(e[i].w&&dis[v]>dis[u]+e[i].c) { dis[v] = dis[u] + e[i].c; minflow=min(minflow,e[i].w); pre[v] = i; if(!vis[v]) { vis[v] = true; que[r++] = v; } } } vis[u] = false; } return dis[sink]!=INF; } int change() { int i,p; for(i=sink; i!=0; i=e[e[p].re].v) { p=pre[i]; e[p].w-=minflow; e[e[p].re].w+=minflow; } flow+=minflow; return minflow*dis[sink]; } int EK() { int sum=0; while(spfa()) sum+=change(); return sum; } void init() { mem(head,-1),mem(pre,0),cnt=0,flow=0; } int main() { int n,m,i,j,a; scanf("%d%d",&n,&m); init(); for(i=1;i<=n;i++) for(j=1;j<=m;j++) { scanf("%d",&a); add(i,n+j,1,-a); } sink=n+m+1; for(i=1;i<=n;i++) add(0,i,1,0); for(i=1;i<=m;i++) add(n+i,sink,1,0); printf("%d\n",-EK()); return 0; }