board (双联通分量)

来源:互联网 发布:免费邮件服务器软件 编辑:程序博客网 时间:2024/05/21 05:39

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 310using 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;}
原创粉丝点击