zoukankan      html  css  js  c++  java
  • 【wikioi】1002 搭桥(dfs+最小生成树)

    http://wikioi.com/problem/1002/

    今天开始又开始刷水了哈T_T。照着hzwer神犇的刷题记录刷!!!

    题解:

    一开始我也不会,但是我想到了直接爆搜T_T。

    好吧,题解。

    首先对于第一个问,我们直接深搜就行了,沿着相连的城市走(ps,这里很坑啊啊啊,左上角和右上角还有左下角右下角也算联通啊!!!一开始我没发现!!)

    那么我们就可以将这些城市看做缩点后的点集x。

    然后我们再爆搜,依次从每个'#'点出发,向四个方向拓展(准确的说是四个方向,每个方向有3行(列)!!),将点集x中不同的点连边,在这里有个剪枝,如果拓展某个方向时,遇到了和自己点集一样的点,那么可以直接停止拓展。理由太简单了,自己想。

    然后连完边后直接跑个最小生成树。

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define rep(i, n) for(int i=0; i<(n); ++i)
    #define for1(i,a,n) for(int i=(a);i<=(n);++i)
    #define for2(i,a,n) for(int i=(a);i<(n);++i)
    #define for3(i,a,n) for(int i=(a);i>=(n);--i)
    #define for4(i,a,n) for(int i=(a);i>(n);--i)
    #define CC(i,a) memset(i,a,sizeof(i))
    #define read(a) a=getnum()
    #define print(a) printf("%d", a)
    #define dbg(x) cout << #x << " = " << x << endl
    inline int getnum() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
    inline const int max(const int &a, const int &b) { return a>b?a:b; }
    inline const int min(const int &a, const int &b) { return a<b?a:b; }
    const int N=60;
    const int dx[8]={0,0,1,1,1,-1,-1,-1}, dy[8]={1,-1,0,1,-1,0,1,-1};
    struct ED { int x, y, w; }e[N*N*N];
    int n, m, a[N][N], d[N][N], ans, sum, cnt, p[N*N];
    inline const bool cmp(const ED &a, const ED &b) { return a.w<b.w; }
    const int ifind(const int &x) { return x==p[x]?x:p[x]=ifind(p[x]); }
    
    void dfs1(const int &x, const int &y) {
    	int fx, fy;
    	d[x][y]=ans;
    	rep(i, 8) {
    		fx=x+dx[i]; fy=y+dy[i];
    		if(fx<1 || fx>n || fy<1 || fy>m || d[fx][fy] || !a[fx][fy]) continue;
    		dfs1(fx, fy);
    	}
    }
    void work1() {
    	for1(i, 1, n) for1(j, 1, m) if(a[i][j] && !d[i][j]) { ++ans; dfs1(i, j); }
    	printf("%d
    ", ans);
    }
    inline const bool insert(const int &fx, const int &fy, const int &x, const int &y, const int &w) {
    	if(x<1 || x>n || y<1 || y>m || !d[x][y]) return 1;
    	if(d[x][y]==d[fx][fy]) return 0;
    	e[++cnt].x=d[fx][fy]; e[cnt].y=d[x][y];
    	e[cnt].w=w-1;
    	return 1;
    }
    void build(const int &x, const int &y) {
    	for1(i, x+1, n) if(!insert(x, y, i, y, i-x) || !insert(x, y, i, y+1, i-x) || !insert(x, y, i, y-1, i-x)) break;
    	for3(i, x-1, 1) if(!insert(x, y, i, y, x-i) || !insert(x, y, i, y+1, x-i) || !insert(x, y, i, y-1, x-i)) break;
    	for1(i, y+1, m) if(!insert(x, y, x, i, i-y) || !insert(x, y, x+1, i, i-y) || !insert(x, y, x-1, i, i-y)) break;
    	for3(i, y-1, 1) if(!insert(x, y, x, i, y-i) || !insert(x, y, x+1, i, y-i) || !insert(x, y, x-1, i, y-i)) break;
    }
    void work2() {
    	for1(i, 1, n) for1(j, 1, m) if(a[i][j]) build(i, j);
    	sort(e+1, e+1+cnt, cmp);
    	for1(i, 1, ans) p[i]=i;
    	sum=ans=0; int fx, fy;
    	for1(i, 1, cnt) {
    		fx=ifind(e[i].x); fy=ifind(e[i].y);
    		if(fx!=fy) {
    			p[fx]=fy;
    			++ans;
    			sum+=e[i].w;
    		}
    	}
    	printf("%d %d
    ", ans, sum);
    }
    
    int main() {
    	read(n); read(m); char c;
    	for1(i, 1, n) for1(j, 1, m) {
    		for(c=getchar(); c!='#'&&c!='.'; c=getchar());
    		if(c=='#') a[i][j]=1;
    	}
    	work1();
    	work2();
    	return 0;
    }
    

    题目描述 Description

    有一矩形区域的城市中建筑了若干建筑物,如果某两个单元格有一个点相联系,则它们属于同一座建筑物。现在想在这些建筑物之间搭建一些桥梁, 其中桥梁只能沿着矩形的方格的边沿搭建,如下图城市1有5栋建筑物,可以搭建4座桥将建筑物联系起来。城市2有两座建筑物,但不能搭建桥梁将它们连接。城 市3只有一座建筑物,城市4有3座建筑物,可以搭建一座桥梁联系两栋建筑物,但不能与第三座建筑物联系在一起。

    输入描述 Input Description

    在输入的数据中的第一行包含描述城市的两个整数r 和c, 分别代表从北到南、从东到西的城市大小(1 <= r <= 50 and 1 <=  c<= 50). 接下来的r 行, 每一行由c 个(“#”)和(“.”)组成的字符. 每一个字符表示一个单元格。“#”表示建筑物,“.”表示空地。

    输出描述 Output Description

    在输出的数据中有两行,第一行表示建筑物的数目。第二行输出桥的数目和所有桥的总长度。

    样例输入 Sample Input

    样例1

    3 5

    #...#

    ..#..

    #...#

    样例2

    3 5

    ##...

    .....

    ....#

    样例3

    3 5

    #.###

    #.#.#

    ###.#

    样例4:

    3 5

    #.#..

    .....

    ....#

    样例输出 Sample Output

    样例1

    5

    4 4

    样例2

    2

    0 0

    样例3

    1

    0 0

    样例4

    3

    1 1

    数据范围及提示 Data Size & Hint

    见描述

  • 相关阅读:
    hdu 1260 Tickets
    hdu 4738 Caocao's Bridges(桥的最小权值+去重)
    找规律
    C语言快速排序
    数组的初始化方法
    C语言选择排序
    副本机制
    安装完Kali的后续操作
    Bool盲注
    Python中的列表
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/3930818.html
Copyright © 2011-2022 走看看