2014 编程之美 预赛第三题 格格取数 上下界费用流
构图比较裸,只是上下界费用流不好做= =
源点向每个行节点连接下界为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; }