JOJ 2662: 采购方案 (二分答案+多重匹配)
CCST@JLU 要举办这次的程序设计大赛。为了节省开支,在各方面都得考虑仔细,比赛场地布置也不例外。在布置场地时,需要为每台电脑提供电源,由于电脑和电源的位置已经固定,所以要采购一些电源线来连接电脑和电源。kkk在采购时发现,购买相同数量的等长电源线总比购买长度不一的电源线要便宜很多(虽然电源线的价格和长度成正比,却不影响这个规律:)),所以kkk决定购买相同长度的电源线来布置场地。kkk想节省开支,你能帮助他么?
题解 :二分答案 + 多重匹配,枚举答案,对小于等于枚举数的边加入到网络中看是否可行,可行就继续找比它小的解 , 不可行就找大一点的解。
多重匹配流的构图,很好想 , 将可多词匹配的点与源汇的连边的权值更改成可匹配的次数即可。
#include <cstdio> #include <cstring> #define max(a,b) (a>b?a:b) #define min(a,b) (a<b?a:b) const int maxn=800; const int inf = 1<<28; const int s=0 ; struct Edge { int v,next,w; }edge[maxn*maxn]; int head[maxn],cnt;//for sap void addedge(int u , int v , int w) { edge[cnt].v=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].v=u; edge[cnt].w=0; edge[cnt].next=head[v]; head[v]=cnt++; } int n,m,cc; /// int sap(int t) { int pre[maxn],cur[maxn]; int dis[maxn],gap[maxn]; int flow=0 , aug=inf ,u; bool flag; for (int i=0 ; i<=t ; ++i) { cur[i]=head[i]; gap[i]=dis[i]=0; } gap[s]=t+1; u=pre[s]=s; while (dis[s]<=t) { flag=0 ; for (int &j=cur[u] ; ~j ; j=edge[j].next) { int v=edge[j].v; if (edge[j].w>0 && dis[u]==dis[v]+1) { flag=1; if(edge[j].w<aug)aug=edge[j].w; pre[v]=u; u=v; if (u==t) { flow+=aug; while (u!=s) { u=pre[u]; edge[cur[u]].w-=aug; edge[cur[u]^1].w+=aug; } aug=inf; } break; } } if (flag)continue ; int mindis=t+1; for (int j=head[u]; ~j ; j=edge[j].next) { int v=edge[j].v; if (edge[j].w>0 && dis[v]<mindis) { mindis=dis[v]; cur[u]=j; } } if(--gap[dis[u]]==0)break; gap[dis[u]=mindis+1]++; u=pre[u]; } return flow; } int map[maxn][maxn]; int c[maxn]; int main () { int cas; scanf("%d",&cas); while (cas--) { scanf("%d%d%d",&n,&m,&cc); for (int i=0 ; i<n ; ++i) { for (int j=0 ; j<m ; ++j) { scanf("%d",map[i]+j); } } int sum=0; for (int i=0 ; i<m ; ++i) { scanf("%d",c+i); sum+=c[i]; } if(sum<n){puts("-1"); continue;} int ans=inf; int l=0,r=10000; /// while (l<=r) { int mid=(l+r)>>1; memset (head , -1 , sizeof(head)); cnt=0; for (int i=0 ; i<n ; ++i) { addedge (0 , i+1 , 1); for (int j=0 ; j<m ; ++j) { if(map[i][j]<=mid) { addedge(i+1,j+n+1,1); } } } for (int j=0 ; j<m ; ++j) addedge(j+n+1 , n+m+1 , c[j]); int match; match=sap(n+m+1); //printf("match = %d\n",match); if(n==match) { r=mid-1; ans=min(ans,mid); } else l=mid+1; } printf("%d\n",ans*cc*n); } return 0; }