每块芯片都被设计成N*N(
N<=40)
的带插槽的正方形。
你需要满足限制如下:
1. 部分插槽不可用
2. 部分插槽已经被组件占据
3. 第i行和第i列组件数目必须相同
4. 对于给出的
A,B
,任何行和列的组件总数不超过芯片上组数的A/B
问最多能再放几个组件。
枚举答案,对于每个答案建立二分图,为了保证条件(3),将右边节点向左边节点连边,如果有解,则
- totcost/inf=C的个数
- totcost%inf=放组件的个数
建图,根据doc老师建的四分图再改成二分图后,
我们得到了这样的无缘无汇最小费用循环流。
无缘无汇最小费用循环流求解:查询图中有无负环,有则满流,无则继续在残余网络上找,直至无负环为止。
spfa时先把所有点压进队列,并假设
di=0
,执行SPFA观察是否有点进队超过
n2
次,这样期望找出负环的时间复杂度大致为
O(n2logn)
(我也不确定)。
由于每次负环最优查询为
O(n2)
,大概可以证明这个程序复杂度
O(n5)
#include<bits/stdc++.h>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,0x3f,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define MEMx(a,b) memset(a,b,sizeof(a));
#define INF (0x3f3f3f3f)
#define F (1000000007)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector<int>
#define pi pair<int,int>
#define SI(a) ((a).size())
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) For(i,n-1) cout<<a[i]<<' '; cout<<a[n]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
For(j,m-1) cout<<a[i][j]<<' ';\
cout<<a[i][m]<<endl; \
}
#pragma comment(linker, "/STACK:102400000,102400000")
#define ALL(x) (x).begin(),(x).end()
#define gmax(a,b) a=max(a,b);
#define gmin(a,b) a=min(a,b);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return ((a-b)%F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
inline int read()
{
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
int n,a,b;
char s[50][50];
int col[50],row[50];
#define MAXN (210)
#define MAXM ((40+40+40*40+40)*2+100)
class Cost_Flow
{
public:
int n,s,t;
int edge[MAXM],Next[MAXM],Pre[MAXN],weight[MAXM],size;
int cost[MAXM];
void addedge(int u,int v,int w,int c)
{
edge[++size]=v;
weight[size]=w;
cost[size]=c;
Next[size]=Pre[u];
Pre[u]=size;
}
void addedge2(int u,int v,int w,int c=0){addedge(u,v,w,c),addedge(v,u,0,-c);}
bool b[MAXN];
int d[MAXN],inq[MAXN];
int pr[MAXN],ed[MAXN];
queue<int> q;
int Find_Negative_Circle()
{
while(!q.empty()) q.pop();
For(i,n) d[i]=inq[i]=0;
For(i,n) q.push(i),inq[i]=1;
int nowv=0;
while(!q.empty()) {
int now=q.front();q.pop();
Forp(now) {
int v=edge[p];
if(weight[p]&&d[now]+cost[p]<d[v]) {
d[v]=d[now]+cost[p];
inq[v]++;
if (inq[v]>n) {
nowv=v;
break;
}
q.push(v);
pr[v]=now,ed[v]=p;
}
}
if (nowv) break;
}
if (!nowv) return 0;
MEM(b)
for(nowv;!b[nowv];nowv=pr[nowv]) {
b[nowv]=1;nowv=pr[nowv];
}
return nowv;
}
int totcost;
int CostFlow()
{
int nowv=0,maxflow=0;
while (nowv=Find_Negative_Circle())
{
int flow=INF,c=0,x=nowv;
do {
c+=cost[ed[x]];
flow=min(flow,weight[ed[x]]);
x=pr[x];
} while(x!=nowv);
if (!c) break;
totcost+=flow*c;
maxflow+=flow;
x=nowv;
do {
weight[ed[x]]-=flow,weight[ed[x]^1]+=flow;
x=pr[x];
}while(x!=nowv);
}
return totcost;
}
void mem(int n,int s,int t)
{
(*this).n=n; (*this).s=s;(*this).t=t;
size=1;
totcost=0;
MEM(Pre) MEM(Next)
}
}S;
int idr[MAXN],idc[MAXN];
int main()
{
// freopen("A.in","r",stdin);
// freopen(".out","w",stdout);
int kcase=1;
while(scanf("%d%d%d",&n,&a,&b)==3 && n) {
MEM(col) MEM(row)
int L=0,R=n*n;
For(i,n) {
scanf("%s",s[i]+1);
For(j,n) {
if (s[i][j]=='C') row[i]++,col[j]++,L++;
if (s[i][j]=='/') --R;
if (s[i][j]=='.') row[i]++,col[j]++;
}
}
int ans=-1;
R=min(R,n*n*a/b);
Fork(f,L,R){
int maxl=f*a/b;
if (f>L) {
if (maxl!=(f-1)*a/b) {
For(i,n) {
int l1=min(maxl,min(col[i],row[i]))-min((f-1)*a/b,min(col[i],row[i]));
S.weight[idr[i]]+=l1;
}
}
} else {
S.mem(2*n,2*n,2*n);
For(i,n) {
S.addedge2(n+i,i,min(maxl,min(col[i],row[i])));
idr[i]=S.size-1;
}
For(i,n) For(j,n) {
if (::s[i][j]=='C') {
S.addedge2(i,n+j,1,-1e6);
} else if (::s[i][j]=='.'){
S.addedge2(i,n+j,1,-1);
}
}
}
int p=S.CostFlow();
if (p==L-f-L*1e6) {
ans=max(ans,f-L);
}
}
printf("Case %d: ",kcase++);
if (ans^-1) printf("%d\n",ans);
else puts("impossible");
}
return 0;
}