分析:
这题的弱化版:ch6802 車的放置
两题的区别在于ch6802禁止的点只是不能放,但是车还是能穿过去的,因此一行最多只能放一个
而hdu1045,也就是这题,禁止的地方是墙,能把两个车隔开
容易想到有墙的存在,一行就可能放两个甚至多个车
如果没有墙,每行共用一个节点标记也就是行数,
有墙的话只要把墙隔开的两边各自标记就行了。
列同理
ps:这题做完之后好像又懂了一点
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
typedef long long ll;
const int inf=0x3f3f3f3f;
const int inn=0x80808080;
using namespace std;
const int maxm=20;
char s[maxm][maxm];
int h[maxm][maxm];//标记行
int l[maxm][maxm];//标记列
vector<int>g[maxm];//存图
int n;
int nn;//行节点总数
int mark[maxm];
int now[maxm];
int dfs(int u){
for(int i=0;i<(int)g[u].size();i++){
int v=g[u][i];
if(!mark[v]){
mark[v]=1;
if(now[v]==0||dfs(now[v])){
now[v]=u;
return 1;
}
}
}
return 0;
}
int main(){
while(cin>>n&&n){
getchar();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
s[i][j]=getchar();
}
getchar();
}
int cnt=1;
memset(h,0,sizeof h);
memset(l,0,sizeof l);
for(int i=1;i<=n;i++){//行标记
for(int j=1;j<=n;j++){
if(s[i][j]=='.'&&h[i][j]==0){
for(int k=j;k<=n;k++){//同一块的标记相同数字
if(s[i][k]=='X'){
break;
}
h[i][k]=cnt;
}
cnt++;
}
}
}
nn=cnt-1;//记录行标记总数量
cnt=1;
for(int i=1;i<=n;i++){//列标记
for(int j=1;j<=n;j++){
if(s[j][i]=='.'&&l[j][i]==0){
for(int k=j;k<=n;k++){//同一块的标记相同数字
if(s[k][i]=='X'){
break;
}
l[k][i]=cnt;
}
cnt++;
}
}
}
for(int i=1;i<=nn;i++){//清空,注意要清空到nn而不是n
g[i].clear();
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(s[i][j]=='.'){
g[h[i][j]].push_back(l[i][j]);
}
}
}
memset(now,0,sizeof now);
int ans=0;
for(int i=1;i<=nn;i++){//直接匈牙利
memset(mark,0,sizeof mark);
ans+=dfs(i);
}
cout<<ans<<endl;
}
return 0;
}