这种限制+求最大方案的题不是网络流就是dp了
dp的话状压可解,但n>20、
首先状态压不下,其次状态的表示是不能通过枚举来记录的,限制条件是有可能精确到块的。
所以就必须考虑网络流,通过决策动态限制方案
这里有一个套路,就是把图拆成行的块和列的块
决策就是选择一个点放置,并用流出限制和这个点冲突的点;
然后就很好建图了
码:
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
#define N 20000
#define inf 1000000009
int zhong[N],hou[N],yuan[N],xia[N],v[N],tot=-1,cnt,d[N],s,t,i,j,n,m,sy[55][55];
char ch[55][55];
void jia(int a,int b,int c)
{
++tot,zhong[tot]=b,hou[tot]=yuan[a],yuan[a]=tot,v[tot]=c;
}
void jian(int a,int b)
{
jia(a,b,1); jia(b,a,0);
}
queue<int>q;
bool bfs()
{
int i;
memset(d,0x7f,sizeof(d));
for(i=1;i<=t;i++)xia[i]=yuan[i];
d[s]=0;
q.push(s);
while(!q.empty())
{
int st=q.front();
q.pop();
for(i=xia[st];i!=-1;i=hou[i])
{
int nd=zhong[i];
if(!v[i]||d[nd]<inf)continue;
d[nd]=d[st]+1;
q.push(nd);
}
}
return d[t]<inf;
}
int dfs(int o,int t,int limit)
{
if(!limit||o==t)return limit;
int i,flow=0,f;
for(i=xia[o];i!=-1;i=hou[i])
{
xia[o]=i;
int nd=zhong[i];
if(d[nd]==d[o]+1&&(f=dfs(nd,t,min(v[i],limit))))
{
flow+=f;
limit-=f;
v[i]-=f;
v[i^1]+=f;
if(!limit)break;
}
}
return flow;
}
int dinic()
{
int ans=0;
while(bfs())
{
ans+=dfs(s,t,inf);
}
return ans;
}
int main()
{
memset(yuan,-1,sizeof(yuan));
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
scanf("%c",&ch[i][j]);
while(ch[i][j]!='*'&&ch[i][j]!='x'&&ch[i][j]!='#') scanf("%c",&ch[i][j]);
}
s=m*n+1;
t=m*n+2;
for(i=1;i<=n;i++)
{
j=1;
while(j<=m)
{
if(ch[i][j]!='#')
{
++cnt;
jian(s,cnt);
while(ch[i][j]!='#'&&j<=m)
{
sy[i][j]=cnt;
++j;
}
}else ++j;
}
}
for(j=1;j<=m;j++)
{
i=1;
while(i<=n)
{
if(ch[i][j]!='#')
{
++cnt;
jian(cnt,t);
while(ch[i][j]!='#'&&i<=n)
{
if(ch[i][j]=='*')jian(sy[i][j],cnt);
++i;
}
}else ++i;
}
} //cout<<cnt<<" ";
printf("%d",dinic());
}