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;}
阅读全文
0 0
- board (双联通分量)
- 浅谈强联通分量,双联通分量
- hdu 5739(点双联通分量 )
- 双联通分量
- 边双联通分量
- 边双联通分量
- 点双联通分量
- 边双联通分量
- 双联通分量 HDU4738
- 双联通分量---点双联通,边双联通 (模板)
- UVALive5796点双联通分量or边双联通分量
- 点双联通分量和边双联通分量小结
- POJ 3177(双联通分量)
- poj3694(边双联通分量)
- HDU 4738 双联通分量
- POJ 1515 双联通分量
- 边双联通分量poj3352
- POJ3177Redundant Paths (双联通分量)
- 基于table的Q learning和Sarsa算法
- java序列化与反序列化(3)------jdk原生序列化机制Externalizable
- MySQL查询语句练习题(50题版)
- Xilinx FPGA 学习笔记——时钟资源
- 浅谈卡尔曼滤波器
- board (双联通分量)
- telnet服务开启
- 好习惯让你健康长寿
- javaWeb之XML解析
- Spring的介绍和理解
- BZOJ 3195: [Jxoi2012]奇怪的道路 状压dp
- 在github下载的java项目通过idea打开(全流程图文,傻瓜式)
- Oracle数据库中的子查询,判断符In、any、all
- POJ