题目:
题目思路,利用并查集去做,注释写的蛮详细。
代码参考:http://www.cnblogs.com/autsky-jadek/p/7287165.html
AC代码:
/*
2017年8月29日22:34:16
Problem L. Canonical duel
二分图+并查集
*/
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
const int maxn=4010;
char mp[maxn][maxn];
int pre[maxn],num[maxn],ans[maxn],mx,x,y,n,m;
int find(int x){
int r=x;
while(pre[r]!=r) r=pre[r];//查找到根节点为止
int i=x,j;
while(i!=r){
j=pre[i];
pre[i]=r;
i=j;
}
return r;
}
void join(int x,int y){
int fx=find(x);
int fy=find(y);
if(fx!=fy) pre[fx]=fy;
//else circle=true; 判断环
}
void init(){
mx=0;
for(int i=1;i<=n+m;i++){
pre[i]=i;
num[i]=0;
ans[i]=0;
}
for(int i=1;i<=n;i++){
scanf("%s",mp[i]+1);
}
/*
test input
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
printf("%c",mp[i][j]);
}printf("\n");
}
*/
/*
如果(1,1)存在一个炸弹+
那么第一行和第一列+1
也就是 num【1】++,num【4】++;
这里1 2 3 行 4 5 6 7 列全部用一维表示
*/
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(mp[i][j]=='+'){
num[i]++;//row
num[j+n]++;//col
}
}
}
}
void solve(){
/*
如果(1,1)存在炸弹+
那么将第一行和第一列连起来
也就是将1 4连起来,形成一个连通分量
*/
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(mp[i][j]=='+'){
join(i,j+n);
}
}
}
/*
开始对不同的联通分量求和 分类
因为每个炸弹对当前行贡献1对当前列贡献1
所以最后答案要除以2
*/
for(int k=1;k<=n+m;k++){
ans[find(k)]+=num[k];
}
//for(int k=1;k<=m+n;k++) printf("ans[%d]=%d\n",k,ans[k]);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(mp[i][j]=='.'){
//找到当前行属于哪一类连通分量
int cur=ans[find(i)];
//如果当前行和当前列属于不同的联通分量,那么将他们加起来
if(find(i)!=find(j+n)){
cur+=ans[find(j+n)];
}
//更新最大值
if((cur/2)>mx){
mx=cur/2;
x=i;
y=j;
}
}
}
}
if(mx){
printf("%d\n",mx);
printf("%d %d",x,y);
}
else printf("0");
}
int main(){
scanf("%d%d",&n,&m);
init();
solve();
return 0;
}