board
10.5 from idy
观察性质 + 双联通分量
先观察到1个性质:只有当陆地数小于等于2时,才无法完成任务。
然后有1个性质:如果陆地数大于等于3,最多只需要删除2个位置,就可以让图变得不连通。(考虑坐标字典序最小的陆地,它的下边和左边一定没有陆地,删掉它右边和上边的它就不连通了,如果只有它和右边及上边,删掉它也不连通了)。
故,我们只需要判断是否可以只删除1个位置让其不连通,50分是枚举1个位置,然后跑flood。
100分是判断图是不是1个双联通分量(Tarjan)。
来自berrykanry的代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std;
struct edge{
int last,v,u;
bool flag;
}ed[400010];
int n,m,T,flag=0,idc=1,cnt=0,idx=0,tot=0,root,mp[330][330],du[330][330];
int head[200010],vis[200010],ins[200010],dfn[200010],low[200010];
char s[100010];
void add(int u,int v){
ed[++idc].v=v;
ed[idc].u=u;
ed[idc].flag=0;
ed[idc].last=head[u];
head[u]=idc;
}
void init()
{
memset(du,0,sizeof(du));
memset(mp,0,sizeof(mp));
memset(head,0,sizeof(head));
memset(vis,0,sizeof(vis));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
flag=idx=tot=0;
idc=1;
}
void build(){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(mp[i][j]){
int S=(i-1)*m+j,A=i*m+j,B=(i-1)*m+j+1;
if(mp[i+1][j])
add(S,A),add(A,S);
if(mp[i][j+1])
add(S,B),add(B,S);
}
}
void tarjan(int u){
dfn[u]=low[u]=++idx;
for(int i=head[u];i;i=ed[i].last){
int v=ed[i].v;
if(ed[i].flag) continue ;
ed[i].flag=ed[i^1].flag=1;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u] && u!=root)
cnt++,flag=1;
}
else
low[u]=min(low[u],dfn[v]);
}
}
int main(){
freopen("board.in","r",stdin);
freopen("board.out","w",stdout);
scanf("%d",&T);
while(T--){
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=m;j++)
if(s[j]=='#'){
mp[i][j]=1,tot++;
du[i-1][j]++,du[i+1][j]++,du[i][j-1]++,du[i][j+1]++;
}
}
if(tot<=2){
printf("-1\n");
continue ;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(mp[i][j] && du[i][j]==1) flag=1;
if(flag==0){
build();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(mp[i][j] && !dfn[(i-1)*m+j] && !flag){
root=(i-1)*m+j;
tarjan((i-1)*m+j);
}
if(cnt) flag=1;
}
if(flag) printf("1\n");
else printf("2\n");
}
return 0;
}
笔者的“歪门邪道”
判断那些点是可以连出去的,对于每个点判断四周是否可以连出去,很好理解的,具体细节看代码吧。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#define LL long long
#define N 310
using namespace std;
int n, m, cnt = 0, flag = 0;
int mp[N][N], du[N][N];
//queue <int>q;
priority_queue<int,vector<int>,greater<int> >q;
int main(){
freopen ("board.in", "r", stdin);
freopen ("board.out", "w", stdout);
int T; scanf("%d", &T);
while ( T-- ){
//init();
cnt = 0; flag = 0;
memset(du, 0, sizeof(du));
memset(mp, 0, sizeof(mp));
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++){
char s[N]; scanf("%s", s+1);
for(int j=1; j<=m; j++){
if(s[j] == '.') {
/*if(mp[i-1][j] == 2 || mp[i][j-1] == 2 || mp[i+1][j] == 2 || mp[i][j+1] == 2 || i==0 || i==n || j==0 || j==m)
mp[i][j] = 2;*/
mp[i][j] = 0;
if(i==0 || i==n || j==0 || j==m){
mp[i][j] = 2;
q.push(i*500 + j);
}
}
else mp[i][j] = 1, cnt++;
}
}
while(!q.empty()){
int cc = q.top(); q.pop();
int y = cc % 500, x = cc / 500;
if(x<n && mp[x+1][y] == 0) mp[x+1][y] = 2, q.push((x+1)*500 + y);
if(y<m && mp[x][y+1] == 0) mp[x][y+1] = 2, q.push((x)*500 + y+1);
if(x>0 && mp[x-1][y] == 0) mp[x-1][y] = 2, q.push((x-1)*500 + y);
if(y>0 && mp[x][y-1] == 0) mp[x][y-1] = 2, q.push((x)*500 + y-1);
if(x<n && y<m && mp[x+1][y+1] == 0) mp[x+1][y+1] = 2, q.push((x+1)*500 + y+1);
if(y<m && x>0 && mp[x-1][y+1] == 0) mp[x-1][y+1] = 2, q.push((x-1)*500 + y+1);
if(y>0 && x<n && mp[x+1][y-1] == 0) mp[x+1][y-1] = 2, q.push((x+1)*500 + y-1);
if(x>0 && y>0 && mp[x-1][y-1] == 0) mp[x-1][y-1] = 2, q.push((x-1)*500 + y-1);
}
if(cnt <= 2) { printf("-1\n"); continue;}
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
if(mp[i][j] == 1){
if(j<m && mp[i][j+1] == 1) du[i][j]++, du[i][j+1]++;
if(i<n && mp[i+1][j] == 1) du[i][j]++, du[i+1][j]++;
}
if(du[i][j] == 1) { printf("1\n"), flag = 1; break;}
if(du[i][j] == 2) {
if(mp[i-1][j] == 1 && mp[i][j-1] == 1 && mp[i-1][j-1] == 2) { printf("1\n"), flag = 1; break;}
if(mp[i-1][j] == 1 && mp[i][j+1] == 1 && mp[i-1][j+1] == 2) { printf("1\n"), flag = 1; break;}
if(mp[i-1][j] == 1 && mp[i+1][j] == 1 && mp[i][j-1] == 2 && mp[i][j+1] == 2) { printf("1\n"), flag = 1; break;}
if(mp[i+1][j] == 1 && mp[i][j-1] == 1 && mp[i+1][j-1] == 2) { printf("1\n"), flag = 1; break;}
if(mp[i+1][j] == 1 && mp[i][j+1] == 1 && mp[i+1][j+1] == 2) { printf("1\n"), flag = 1; break;}
if(mp[i][j-1] == 1 && mp[i][j+1] == 1 && mp[i-1][j] == 2 && mp[i+1][j] == 2) { printf("1\n"), flag = 1; break;}
}
if(du[i][j] == 3){
int cc = 0;
if(mp[i-1][j] != 1) {
if(mp[i+1][j-1] == 2) cc++;
if(mp[i+1][j+1] == 2) cc++;
if(mp[i-1][j] == 2) cc++;
if(cc >= 2) { printf("1\n"), flag = 1; break;}
}
if(mp[i+1][j] != 1) {
if(mp[i-1][j-1] == 2) cc++;
if(mp[i-1][j+1] == 2) cc++;
if(mp[i+1][j] == 2) cc++;
if(cc >= 2) { printf("1\n"), flag = 1; break;}
}
if(mp[i][j-1] != 1) {
if(mp[i+1][j+1] == 2) cc++;
if(mp[i-1][j+1] == 2) cc++;
if(mp[i][j] == 2) cc++;
if(cc >= 2) { printf("1\n"), flag = 1; break;}
}
if(mp[i][j+1] != 1) {
if(mp[i+1][j-1] == 2) cc++;
if(mp[i-1][j-1] == 2) cc++;
if(mp[i][j+1] == 2) cc++;
if(cc >= 2) { printf("1\n"), flag = 1; break;}
}
}
if(du[i][j] == 4){
int cc = 0;
if(mp[i+1][j-1] == 2) cc++;
if(mp[i-1][j-1] == 2) cc++;
if(mp[i+1][j+1] == 2) cc++;
if(mp[i-1][j+1] == 2) cc++;
if(cc >= 2) { printf("1\n"), flag = 1; break;}
}
}
if(flag == 1) break;
}
if(flag != 1) printf("2\n");
}
return 0;
}