【八中】最少连通代价(mincon.cpp)
来源:互联网 发布:pptv网络电视怎么用 编辑:程序博客网 时间:2024/05/01 07:37
3.最少连通代价(mincon.cpp)
声明:本博客为博主原创,未经允许,不得转载。
在一个 N 行 M 列的字符网格上,恰好有 2 个彼此分开的连通块。每个连通 块的一个格点与它的上、下、左、右的格子连通。如下图所示:
现在要把这 2 个连通块连通,求最少需要把几个’.’转变成’X’。上图的例子中, 最少只需要把 3 个’.’转变成’X’。下图用’*’表示转化为’X’的格点。
Input
第 1 行:2 个整数 N 和 M(1<=N,M<=50)
接下来 N 行,每行 M 个字符,’X’表示属于某个连通块的点,’.’表示不属于某个连通块的格点。
Output
第 1 行:1 个整数,表示最少需要把几个’.’转变成’X’
Sample Input
6 16..................XXXX....XXX......XXXX....XX....XXXX......XXX..........XXXXX............XXX....
Sample Output
3
解析:
在完成此题时,我们可以用深搜+广搜,也或者只用一个深搜。但在此之前,你必须明白曼哈顿距离。如下图:
如果你明白了,那你也就应该知道了,为什么可以只用一个深搜了。
代码大解析:
(1)深搜+广搜
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int n,m,pre[1000000],a[1000000],b[1000000],minn,ans=1e10;int x[4]={1,-1,0,0},y[4]={0,0,1,-1};char map[100][100];bool mark[100][100];bool check(int s,int t){ if(s&&t&&s<=n&&t<=m&&!mark[s][t]&&map[s][t]!='S') return 1; return 0;}void fun(int d){ minn++; if(pre[d]) fun(pre[d]);}void bfs(int r,int c){ memset(mark,0,sizeof(mark)); minn=0; int head=0,tail=1; int nextr,nextc; mark[r][c]=1; pre[1]=0; a[1]=r; b[1]=c; while(head!=tail) { head++; for(int i=0;i<4;i++) { nextr=a[head]+x[i]; nextc=b[head]+y[i]; if(check(nextr,nextc)) { tail++; a[tail]=nextr; b[tail]=nextc; mark[nextr][nextc]=1; pre[tail]=head; if(map[nextr][nextc]=='X') { fun(tail); ans=min(minn,ans); } } } }}void dfs(int r,int c){ for(int i=0;i<4;i++) if(check(r+x[i],c+y[i])&&map[r+x[i]][c+y[i]]!='.') { mark[r+x[i]][c+y[i]]=1; map[r+x[i]][c+y[i]]='S'; dfs(r+x[i],c+y[i]); mark[r+x[i]][c+y[i]]=0; }}void f(){ for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(map[i][j]=='X') { dfs(i,j); map[i][j]='S'; return ; }}int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%s",map[i]+1); bool flag=1; f(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(map[i][j]=='S') bfs(i,j); printf("%d",ans-2);}
(2)深搜(平民版)
#include <cstdio>#define MAXN 55#define MAXM 55char G[MAXN][MAXM];int N, M;void dfs(int r, int c, char ch)//深搜,把第一个连通块变为1,把第二个连通块变为2{ if (G[r][c]!='X') return;//当不等于'X'时,退出 G[r][c] = ch;//模仿走路 if (r>0) dfs(r-1,c,ch); if (c>0) dfs(r,c-1,ch); if (r<N-1) dfs(r+1,c,ch); if (c<M-1) dfs(r,c+1,ch);}int abs(int x)//取绝对值{ if (x>=0) return x; return -x;}int mindist(void){ int r1, r2, c1, c2, min=MAXN+MAXM;//min=110 for (r1=0; r1<N; r1++) for (c1=0; c1<M; c1++) if (G[r1][c1]=='1') for (r2=0; r2<N; r2++) for (c2=0; c2<M; c2++) if (G[r2][c2]=='2')//保证了r1,r2,c1,c2为连通块的坐标 if (abs(r1-r2) + abs(c1-c2) < min)//取最小路径 min = abs(r1-r2) + abs(c1-c2);//(曼哈顿距离) return min - 1;}int main(void){ int r, c; char ch='0'; scanf ("%d %d", &N, &M); for (r=0; r<N; r++) scanf ("%s", &G[r]); for (r=0; r<N; r++) for (c=0; c<M; c++) if (G[r][c] == 'X') //如果是'X'的话,就深搜 dfs(r,c,++ch); printf ("%d\n", mindist());//找到最小路径 return 0;}
(3)深搜(大神版)
#include<cstdio>#include<vector>#include<cmath>#include<algorithm>using namespace std;struct Da{int x,y;} D;//坐标vector<Da> vec[2];//结构体的动态数组char map[55][55];int F[4][2]={{1,0},{-1,0},{0,1},{0,-1}},r,c,S;void flag(int x,int y){ D.x=x;D.y=y;//赋值,记录下来 vec[S].push_back(D);//把D.X和D.y压进ves数组里 map[x][y]='.';//变成点点 for(int i=0;i<4;i++)//深搜,完成第一个连通块 { int sx=x+F[i][0],sy=y+F[i][1]; if(0<=sx && sx<r && 0<=y && y<c && map[sx][sy]=='X') flag(sx,sy);//走路 }}int main(){ scanf("%d%d",&r,&c);//输入 for(int i=0;i<r;i++) scanf("%s",map[i]);//因为没有打‘ ’,所以用‘%s’ for(int i=0;i<r;i++) for(int j=0;j<c;j++) if(map[i][j]=='X') /* 当第一次找到它的时候,就深搜,并把它们都变成点点, 那当第二次找到它的时候,就一定是另外一个连通块。 */ { flag(i,j);//深搜 S++;//当s==0时,就一定为第一个;当s==1时,就为第二个(连通块)。 } int la=vec[0].size(),lb=vec[1].size(),ans=1e8; for(int i=0;i<la;i++) for(int j=0;j<lb;j++)//找到最小的(曼哈顿距离) ans=min(ans,int(fabs(vec[0][i].x-vec[1][j].x)+fabs(vec[0][i].y-vec[1][j].y)-1));//减一减去重复的块 printf("%d\n",ans);//输出 return 0;}
思想大开发:
在完成此题时,还有另外一种方法如下图所示:
如果有兴趣的同学,可以完成这种做法,然后发至评论。
阅读全文
0 1
- 【八中】最少连通代价(mincon.cpp)
- C++搜索算法和曼哈顿距离之最少连通代价
- 考试题目讲解-【第3题】最少连通代价
- HDU 4313 Matrix(并查集/破坏边使得k个点两两不连通的最少代价)
- 最少联通代价【曼哈顿距离】
- 【八中】打怪(fight.cpp)
- 四连通与八连通
- 四连通与八连通
- 四连通与八连通
- 【八中】三角形划分平面区域(tripar.cpp)
- 寻找八连通区域
- HNACM(八)C-最少换乘
- PostgreSQL查询代价估算(八)
- 1408111053-hd-最少拦截系统.cpp
- Summer Holiday 【有向图中连通最少的点来使其整个图 连通的】+【tarjan求SCC +缩点】
- HDU 2767--Proving Equivalences【scc缩点构图 && 求向图中最少增加多少条边才可以使新图强连通】
- Cpp环境【CQYZOJ3531】【CQNOI2016模拟赛(八中出题)】约瑟夫の秘制游戏
- 代价
- Windows 版 SourceTree 免登录跳过初始设置的方法
- HDU1800
- 嵌入式linux/qt开发:RFID智能仓储指纹管理系统
- PostgreSQL,MongoDB,Neo4j,OrientDB和ArangoDB比较
- Android WebView的各种load方法
- 【八中】最少连通代价(mincon.cpp)
- node.js之soketio
- LINQ语句小结
- 谈谈ThreadLocal和解决线程安全的关系
- 【转】Tomcat webapps下面的东西都可以删除吗
- protobuf3语言指南
- compileSdkVersion targetSdkVersion minSdkVersion的关系
- 基类实现求体积、表面积
- Kaggle房价预测:数据探索——练习