2020/10/23 模拟赛 chip

Description

一张$n \times n$的芯片上,有些格子己经焊有零件,有些格子禁止焊接零件。问,在同时满足下面 三个约束的前提下,至多可以再焊接多少个零件。

1. 每个格子至多焊接一个零件
2. 第$i$行的零件总数和第$i$列一致
3. 任意一行的零件数不得超过总零件数的$\frac AB$

Solution

带负环的费用流

枚举总零件数的$\frac AB$,建图跑费用流,设$hangnum$为第$i$行一开始就有的零件数

  1.  从第$i$行向第$i$列连边,容量为$lim-hangnum_i$,费用为$0$
  2.  若$hangnum > lienum$,从$S$连向第$i$列,容量为$delta$,费用为$0$
  3.  若$hangnum < lienum$,从第$i$行连向$T$,容量为$delta$,费用为$0$
  4.  若$(i,j)$可以放置,从第$j$列连向第$i$行,容量为$1$,费用为$0$

最小费用最大流的相反数即为答案

但是会出现负环,所以要先走一遍负环

将原图中每个点拆成入点和出点,对应的每一条边在新图中由入点连向出点,可以保证所有负环不再组成负环,被拆分成多条独立的路径,原来的路径一定不在最大流中、

在新图中跑最小费用最大流就可以计算所有负环的费用,再对应着将流量改回原图,在该残余网络上跑最小费用最大流就不会陷入死循环

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<cmath>
using namespace std;
int n,A,B,delta[45],hangcan[45],liecan[45],hangnum[45],lienum[45],total,ans=-1,cnt;
const int INF=0x7f7f7f7f;
char map[45][45];
struct Edge
{
    int head[355],nxt[50005],to[50005],w[50005],dis[50005],sta[50005],dist[355],tot,S,T;
    bool vst[355];
    void clear()
    {
        memset(head,0,sizeof(head));
        tot=1;
    }
    void addedge(int u,int v,int c,int d)
    {
        nxt[++tot]=head[u];
        head[u]=tot;
        to[tot]=v;
        sta[tot]=u;
        w[tot]=c;
        dis[tot]=d;
        nxt[++tot]=head[v];
        head[v]=tot;
        to[tot]=u;
        sta[tot]=v;
        w[tot]=0;
        dis[tot]=-d;
    }
    bool SPFA(int s,int t)
    {
        memset(dist,127,sizeof(dist));
        memset(vst,false,sizeof(vst));
        queue<int>q;
        vst[s]=true;
        dist[s]=0;
        q.push(s);
        while(q.size())
        {
            int u=q.front();
            q.pop();
            for(int i=head[u];i;i=nxt[i])
            {
                int v=to[i];
                if(w[i]>0&&dist[v]>dist[u]+dis[i])
                {
                    dist[v]=dist[u]+dis[i];
                    if(!vst[v])
                    {
                        vst[v]=true;
                        q.push(v);
                    }
                }
            }
            vst[u]=false;
        }
        return dist[t]<INF;
    }
    int DFS(int s,int flow,int t)
    {
        if(s==t||flow<=0)
        {
            return flow;
        }
        int rest=flow;
        vst[s]=true;
        for(int i=head[s];i;i=nxt[i])
        {
            int v=to[i];
            if(w[i]>0&&dist[s]+dis[i]==dist[v]&&!vst[v])
            {
                int k=DFS(v,min(rest,w[i]),t);
                rest-=k;
                w[i]-=k;
                w[i^1]+=k;
                if(rest<=0)
                {
                    break;
                }
            }
        }
        return flow-rest;
    }
    void ZKW(int &costs)
    {
        while(SPFA(S,T))
        {
            memset(vst,false,sizeof(vst));
            costs+=dist[T]*DFS(S,INF,T);
        }
    }
    bool check()
    {
        for(int i=head[S];i;i=nxt[i])
        {
            if(!(i&1)&&w[i])
            {
                return false;
            }
        }
        return true;
    }
}G1,G2;
inline int read()
{
    int f=1,w=0;
    char ch=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        w=(w<<1)+(w<<3)+ch-'0';
        ch=getchar();
    }
    return f*w;
}
int X(int a,int t)
{
    return a*2+t+1;
}
int xiaoquan()
{
    G2.T=320;
    for(int i=2;i<=G1.tot;i+=2)
    {
        G2.addedge(X(G1.sta[i],0),X(G1.to[i],1),G1.w[i],G1.dis[i]);
    }
    for(int i=0;i<=G1.T;i++)
    {
        if((i>n&&i<100)||(i>100+n&&i<G1.T))
        {
            continue;
        }
        G2.addedge(G2.S,X(i,0),INF,0);
        G2.addedge(X(i,1),G2.T,INF,0);
        G2.addedge(X(i,0),X(i,1),INF,0);
    }
    int costs=0;
    G2.ZKW(costs);
    for(int i=2;i<=G1.tot;i+=2)
    {
        int del=G1.w[i]-G2.w[i];
        G1.w[i]-=del;
        G1.w[i^1]+=del;
    }
    return -costs;
}
void calc(int lim)
{
    G1.clear();
    G2.clear();
    for(int i=1;i<=n;i++)
    {
        if(lienum[i]>lim||hangnum[i]>lim)
        {
            return;
        }
    }
    G1.S=G2.S=0;
    G1.T=G2.T=153;
    for(int i=1;i<=n;i++)
    {
        G1.addedge(i,i+100,lim-hangnum[i],0);
        if(delta[i]>0)
        {
            G1.addedge(G1.S,i+100,delta[i],0);
        }
        else if(delta[i]<0)
        {
            G1.addedge(i+100,G1.T,-delta[i],0);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(map[i][j]=='.')
            {
                G1.addedge(j+100,i,1,-1);
            }
        }
    }
    int ttt=xiaoquan(),costs=0;
    G1.ZKW(costs);
    if(!G1.check())
    {
        return;
    }
    ttt-=costs;
    if((double)(ttt+cnt)*A/B>=lim)
    {
        ans=max(ans,ttt);
    }
}
int main()
{
    n=read();
    A=read();
    B=read();
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            map[i][j]=getchar();
            if(map[i][j]=='C')
            {
                ++total;
                ++cnt;
                ++delta[i];
                --delta[j];
                ++hangnum[i];
                ++lienum[j];
                ++hangcan[i];
                ++liecan[j];
            }
            else if(map[i][j]=='.')
            {
                ++total;
                ++hangcan[i];
                ++liecan[j];
            }
        }
        getchar();
    }
    for(int i=1;i<=n;i++)
    {
        if(hangnum[i]>(double)total*A/B||min(hangcan[i],liecan[i])<max(hangnum[i],lienum[i]))
        {
            puts("impossible");
            return 0;
        }
    }
    for(int i=n;i>=1;i--)
    {
        calc(i);
        if(ans!=-1)
        {
            break;
        }
    }
    if(ans==-1)
    {
        for(int i=1;i<=n;i++)
        {
            if(delta[i]||hangnum[i]>(double)cnt*A/B)
            {
                puts("impossible");
                return 0;
            }
        }
        puts("0");
        return 0;
    }
    printf("%d\n",ans);
    return 0;
}
chip

 

posted @ 2020-11-05 19:58  QDK_Storm  阅读(100)  评论(0编辑  收藏  举报