题目:https://loj.ac/problem/2979

原来的思路:

  优化连边。一看就是同一个桌子相邻座位之间连边、相邻桌子对应座位之间连边。

  每个座位向它所属的桌子连边。然后每个人建一个点,向若干桌子连边。

  因为连边的桌子是区间,所以线段树优化。

  又想到志愿者招募之类的,所以想弄一个上下界费用流。人向它的座位连下界为1的边,对应桌子区间向人连边。找一些循环流。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ls Ls[cr]
#define rs Rs[cr]
using namespace std;
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
int Mn(int a,int b){return a<b?a:b;}
const int N=305,M=15,N2=7000,M2=140000,INF=3005;
int n,m,S,T,L[N][M],R[N][M],dy[N],bh[N][M],tot,Ls[N<<1],Rs[N<<1];
int rd[N2],hd[N2],xnt=1,to[M2],nxt[M2],cap[M2],w[M2];
int ans,dis[N2],pr[N2],info[N2]; bool ins[N2];
queue<int> q;
void add(int x,int y,int l,int r,int z)
{
  rd[y]+=l; rd[x]-=l; ans+=l*z; r-=l;
  to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;cap[xnt]=r;w[xnt]=z;
  to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;cap[xnt]=0;w[xnt]=-z;
}
void build(int l,int r,int cr)
{
  if(l==r){dy[l]=cr;return;}
  int mid=l+r>>1;
  ls=++tot; build(l,mid,ls);
  rs=++tot; build(mid+1,r,rs);
  add(ls,cr,0,INF,0); add(rs,cr,0,INF,0);
}
void qry(int l,int r,int cr,int L,int R,int k)
{
  if(l>=L&&r<=R)
    {
      printf("(%d->%d)\n",cr,k);
      add(cr,k,0,1,0);return;
    }
  int mid=l+r>>1;
  if(L<=mid)qry(l,mid,ls,L,R,k);
  if(mid<R)qry(mid+1,r,rs,L,R,k);
}
bool spfa()
{
  memset(dis,0x3f,sizeof dis); info[T]=0;
  dis[S]=0; info[S]=INF; q.push(S); ins[S]=1;
  while(q.size())
    {
      int k=q.front(); q.pop(); ins[k]=0;
      for(int i=hd[k],v;i;i=nxt[i])
    if(cap[i]&&dis[v=to[i]]>dis[k]+w[i])
      {
        dis[v]=dis[k]+w[i];
        pr[v]=i; info[v]=Mn(info[k],cap[i]);
        if(!ins[v])ins[v]=1,q.push(v);
      }
    }
  return info[T];
}
int ek()
{
  int tp=info[T];
  for(int i=pr[T];i;i=pr[to[i^1]])
    {
      cap[i]-=tp; cap[i^1]+=tp;
      ans+=w[i]*tp;
      printf("%d ",to[i]);
    }
  puts("");
  return tp;
}
int main()
{
  n=rdn();m=rdn();
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)L[i][j]=rdn()+1;//+1
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)R[i][j]=rdn()+1;
  tot=1;build(1,n,1); int tmp=n*m;
  for(int i=1;i<=n;i++,puts(""))
    for(int j=1;j<=m;j++)bh[i][j]=++tot,printf("%d ",tot);
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
      {
    qry(1,n,1,L[i][j],R[i][j],bh[i][j]+tmp);
    printf("(%d->%d)\n",bh[i][j]+tmp,bh[i][j]);
    add(bh[i][j]+tmp,bh[i][j],1,1,0);
    printf("(%d->%d)\n",bh[i][j],dy[i]);
    add(bh[i][j],dy[i],1,1,0);

    printf("(%d->%d)[]\n",bh[i][j],bh[i][j==m?1:j+1]);
    add(bh[i][j],bh[i][j==m?1:j+1],0,INF,1);
    printf("(%d->%d)[]\n",bh[i][j],bh[i][j>1?j-1:m]);
    add(bh[i][j],bh[i][j>1?j-1:m],0,INF,1);
    if(i<n)
      {
        printf("(%d->%d)[]\n",bh[i][j],bh[i+1][j]);
        add(bh[i][j],bh[i+1][j],0,INF,2);
      }
      }
  tot+=tmp; S=tot+1; T=tot+2; tmp=0;
  printf("S=%d T=%d\n",S,T);
  for(int i=1;i<=tot;i++)
    if(rd[i]<0)add(i,T,0,-rd[i],0);
    else if(rd[i]>0)add(S,i,0,rd[i],0),tmp+=rd[i];
  printf("tmp=%d ans=%d\n",tmp,ans);
  while(spfa())tmp-=ek();
  if(tmp)puts("no solution");
  else printf("%d\n",ans);
  return 0;
}
View Code

相关文章:

  • 2022-12-23
  • 2021-11-02
  • 2021-06-18
  • 2022-01-28
  • 2021-09-19
  • 2021-12-26
  • 2021-06-25
猜你喜欢
  • 2021-12-02
  • 2021-12-23
  • 2021-07-02
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案