#费用流#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;
} 
posted @ 2025-06-12 14:09  lemondinosaur  阅读(5)  评论(0)    收藏  举报