POJ 2386 动态规划

问题描述:row*col的矩阵表示一块田地,上面的'W'代表积水,'.'表示干地,问这块田地里面的积水能汇聚成几片水洼


我的动态规划解法:

子问题:前K个元素形成的水洼数

递推关系:对于第K个元素,考虑其左,左上,上,右上四个方向的元素,如果只存在一个水洼则将第K个元素加入此水洼,如果存在2个水洼,则只能是左方和右上方(因为左上方和上方的已经在子问题中解决),因为第K个元素,这两个水洼会合并(dele变量记录合并了多少次)

AC后去网上搜了搜解法,发现大神们直接用图的深度优先遍历解决了,而且时间、内存更少。好吧(在网上看的帖子将此题分为了动态规划类,直接去想子问题,没想到去与图的遍历联系(而且想到了递归,但是不想用递归),所以就直接DP解决了。下面先给出大神的代码,在给出我的代码。

  • 大神的代码:192K 0ms
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <queue>
    using namespace std;
    
    #define maxn 106
    
    struct XPoint
    {
        int x;
        int y;
        XPoint(int xx, int yy) :
            x(xx), y(yy)
        {
        }
        XPoint()
        {
        }
    };
    
    int n, m;
    bool map[maxn][maxn];
    bool vis[maxn][maxn];
    int ans;
    int dir[8][2] =
    {
    { -1, -1 },
    { -1, 0 },
    { -1, 1 },
    { 0, -1 },
    { 0, 1 },
    { 1, -1 },
    { 1, 0 },
    { 1, 1 } };
    
    bool ok(int x, int y)
    {
        if (x < 0 || y < 0 || x >= n || y >= m)
            return false;
        if (vis[x][y])
            return false;
        return map[x][y];
    }
    
    void work(int x, int y)
    {
        ans++;
        queue<XPoint> q;
        q.push(XPoint(x, y));
        vis[x][y] = true;
        while (!q.empty())
        {
            XPoint temp = q.front();
            q.pop();
            for (int i = 0; i < 8; i++)
                if (ok(temp.x + dir[i][0], temp.y + dir[i][1]))
                {
                    vis[temp.x + dir[i][0]][temp.y + dir[i][1]] = true;
                    q.push(XPoint(temp.x + dir[i][0], temp.y + dir[i][1]));
                }
        }
    }
    
    int main()
    {
        //freopen("t.txt", "r", stdin);
        scanf("%d%d", &n, &m);
        memset(map, 0, sizeof(map));
        memset(vis, 0, sizeof(vis));
        ans = 0;
        getchar();
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                char ch;
                scanf("%c", &ch);
                if (ch == 'W')
                    map[i][j] = true;
            }
            getchar();
        }
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                if (!vis[i][j] && map[i][j])
                    work(i, j);
        printf("%d\n", ans);
        return 0;
    }
我的代码:404K  94ms

#include <iostream>
#include <string>
using namespace std;
struct element
{
	bool water;
	int row;
	int col;
	int id;
};

void update_pondid(int row, int col, element ** arr,int arrrow, int arrcol,int oldid,int newid)
{
	int i;
	int j;
	for (  i = 0; i <= row; i++ )
	{
		for ( j = 0; j < arrcol; j++ )
		{
			if(arr[i][j].id == oldid )
				arr[i][j].id = newid;
		}
	}

}

void Around_Judge(int row, int col, element ** arr,int arrrow, int arrcol,int *pondcount,int * ponddelete)
{
	if(arr[row][col].water)
	{
		int l = -1, rt = -1;
		int id = -1;
		bool re = false;
		
		if( (col - 1) >= 0 && arr[row][col-1].water )
		{
			id = l = arr[row][col-1].id;
			re = true;
		}
			
		if( (col - 1) >= 0 && (row - 1) >= 0 && arr[row-1][col-1].water )
		{
			id = arr[row-1][col-1].id;
			re = true;
		}
		if( (row - 1) >= 0 && arr[row-1][col].water )
		{
			id = arr[row-1][col].id;
			re = true;
		}
		if( (col + 1) < arrcol && (row - 1) >= 0 && arr[row-1][col+1].water)
		{
			rt = arr[row-1][col+1].id;
			re = true;
		}
		if(!re)
		{
			*pondcount +=1;
			arr[row][col].id = *pondcount;
		}
		else if( id != -1 && rt != -1 && id != rt )
		{
			arr[row][col].id = id;
			update_pondid(row, col, arr,arrrow,arrcol,rt,id);
			*ponddelete +=1;
		}
		else
		{
			id > rt ? arr[row][col].id = id: arr[row][col].id = rt;
		}
	}
}
int main()
{
	int r = 0 , c = 0 ;
	cin>>r>>c;
	element **arr = new element*[r];
	for(int i = 0; i < r; i++ )
		arr[i] = new element[c];
	//初始化
	int i;
	int j;
	for (  i = 0; i < r; i++ )
	{
		for ( j = 0; j < c; j++ )
		{
			char t;
			cin>>t;
			element ele = {false,i,j,0};
			if( t == 'W' )
				ele.water = true;
			arr[i][j] = ele;
		}
	}
	int * count = new int;
	*count = 1;
	int * dele = new int;
	*dele = 1;
	for (  i = 0; i < r; i++ )
	{
		for ( j = 0; j < c; j++ )
		{
			Around_Judge(i,j,arr,r,c,count,dele);
		}
	}
	cout<<(*count) - (*dele) <<endl;
	
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值