#费用流#UVA1104 芯片难题 Chips Challenge
分析
考虑如何同时满足两个限制,那么也许就要枚举每行每列最多放多少个部件,那怎样求总部件的个数呢?
源点向行连费用为 \(0\),容量为该行最多装入部件的个数;列向汇点连相同的边。
那怎样求出呢,每行向相同的列连费用为 \(0\),容量为枚举的部件数,表示选择了在行列放下的部件数,
而如果行向对应的列连费用为 \(1\),容量为 \(1\) 的边,表示在这个可放入部件的位置不选择放入。
那么满流才能满足行列个数相等的情况,否则枚举的部件数不够;在这基础上用多余放入的位置减去费用就是总部件个数,那么满足两个条件就能贡献答案。
代码
#include <cstdio>
#include <cctype>
#include <cstring>
#include <queue>=
using namespace std;
const int N=111,inf=0x3f3f3f3f; queue<int>q;
struct node{int y,w,f,next;}e[N<<5]; char str[N];
int as[N],dis[N],v[N],dep[N],n,m,S,T,et=1,ans,A,B,Test,ANS,flag,sum,SUM,srow[N],scol[N];
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
void add(int x,int y,int w,int f){
e[++et]=(node){y,w,f,as[x]},as[x]=et;
e[++et]=(node){x,0,-f,as[y]},as[y]=et;
}
bool spfa(){
for (int i=1;i<=T;++i) dis[i]=inf,v[i]=0,dep[i]=0;
dis[T]=0,v[T]=1,q.push(T);
while (!q.empty()){
int x=q.front(); q.pop();
for (int i=as[x];i;i=e[i].next)
if (e[i^1].w&&dis[e[i].y]>dis[x]-e[i].f){
dis[e[i].y]=dis[x]-e[i].f,dep[e[i].y]=dep[x]+1;
if (!v[e[i].y]) v[e[i].y]=1,q.push(e[i].y);
}
v[x]=0;
}
return dis[S]<inf;
}
int dfs(int x,int now){
if (x==T) {v[T]=1; return now;}
int rest=0,f; v[x]=1;
for (int i=as[x];i;i=e[i].next)
if (!v[e[i].y]&&e[i].w&&dep[e[i].y]==dep[x]-1&&dis[e[i].y]+e[i].f==dis[x]){
rest+=(f=dfs(e[i].y,min(e[i].w,now-rest)));
if (f) ANS+=f*e[i].f,e[i].w-=f,e[i^1].w+=f;
if (rest==now) break;
}
return rest;
}
int maxflow(){
int ans=0;
while (spfa()){
v[T]=1;
while (v[T]){
memset(v,0,sizeof(v));
ans+=dfs(S,inf);
}
}
return ans;
}
int main(){
while (1){
scanf("%d%d%d",&n,&A,&B),S=n<<1|1,T=S+1,++Test,et=1,flag=SUM=sum=0;
if (!n) break;
for (int i=1;i<=n;++i) add(i,i+n,0,0);
for (int i=1;i<=n;++i){
scanf("%s",str+1);
for (int j=1;j<=n;++j)
if (str[j]!=47){
++sum,++srow[i],++scol[j];
if (str[j]=='C') ++SUM;
else add(i,j+n,1,1);
}
}
for (int i=1;i<=n;++i) add(S,i,srow[i],0),add(i+n,T,scol[i],0);
for (int flow=n;~flow;--flow){
for (int i=2;i<=et;i+=2) e[i].w+=e[i^1].w,e[i^1].w=0;
for (int i=1;i<=n;++i) e[i<<1].w=flow;
ANS=0;
if (maxflow()==sum&&(sum-ANS)*A>=flow*B){
printf("Case %d: %d\n",Test,sum-SUM-ANS);
flag=1;
break;
}
}
if (!flag) printf("Case %d: impossible\n",Test,ans);
for (int i=1;i<=n;++i) srow[i]=scol[i]=0;
for (int i=1;i<=T;++i) as[i]=0;
}
return 0;
}

浙公网安备 33010602011771号