大家帮我看个算法

coffeegg 2009-11-26 08:25:49
有25个珠子,编号为1-25
共有有5种颜色(各种颜色数量随机)
组成一个5*5的矩阵
要找出其中所有 同色相邻的集合
相邻的集合 是指 1跟2相邻 2跟3相邻 而不再与其他同色的相邻
则集合就是123

要求:(c++编写)算法最大程度优化(cpu时间少)
...全文
430 33 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
33 条回复
切换为时间正序
请发表友善的回复…
发表回复
云霄 2009-12-02
  • 打赏
  • 举报
回复
想了一个方法,就是自己写一个琏表,这样就不用一个一个的pushback了。

[Quote=引用 10 楼 coffeegg 的回复:]
恩,不错,不过本身算法有问题,我举个例子吧(下面1为1种颜色,2为另一种颜色)
1 1 1 1 1
2 2 2 2 1
2 1 2 1 1
2 1 1 1 1
2 2 2 2 2
这里的(3,2) 与(3,4)还有其他的点不会放在一个集合里,但是实际在上面的情况里,所有的1都是放在一个集合里的
对于(3,5)这个点,他发现左边和上边的index不一样,所以你的代码就出问题了
当然,可以解决的是,当发现左边和上边的点颜色一样而index不一样,就把他们pushback到同一个容器,但是很浪费效率
跟我每个点都判断4个方向几乎没区别了
引用 6 楼 easypal 的回复:
上面的代码忘了编译,
下面的代码是编译通过的

C/C++ code/*
算法思想:
维护一个所有同色相邻珠子集合的容器,和一个标记每个珠子属于哪个集合的二维数组
依次检查每一个珠子,如果与已分配集合的珠子(具体点,就是上方的 和 左边的)颜色相同,就把这个珠子加入到此集合
否则为该珠子分配一个新的集合。
当检查完每个珠子,那么每个珠子都分派到一个集合。

证明:反证
算法结束后,如果存在两个相邻且颜色相同的珠子B,C没有在同一个集合SB中,设珠子B在C的左上方。
那么珠子C在B的右下方,并且与B的颜色相同。根据算法结果,C与B在同一个集合中。矛盾产生。*/


#include <iostream>
#include <vector>usingnamespace std;constint MAXN=5;//矩形的边长
vector < vector <int>> s;//开辟一个vector <vector <int>>类型s容器,用于维护所有的集合;int index[MAXN][MAXN];//一个数组Index,保存每个珠子集合的的序号int color[MAXN][MAXN];//珠子的颜色数组int main()
{int n= MAXN;//初始化珠子数组的颜色for(int k=0; k <n; k++)
    {for(int l=0; l <n; l++)
        {
            color[k][l]= k*l%5;
        }
    }//核心代码for(int i=0;i <n;i++)
    {for(int j=0;j <n;j++)
        {if(i-1>=0&&color[i-1][j]==color[i][j])//如果此珠子与上方的珠子相同            {
                index[i][j]= index[i-1][j];//标记i*n+j+1珠子与上方的珠子同属于一个集合                s[index[i][j]].push_back(i*n+j+1);//将第i*n+j+1珠子加入所在集合            }elseif(j-1>=0&& color[i][j-1]== color[i][j])//如果此珠子与左边的珠子相同            {
                index[i][j]= index[i][j-1];//标记i*n+j+1珠子与左边珠子同属于一个集合                s[index[i][j]].push_back(i*n+j+1);//将第i*n+j+1珠子加入所在集合            }else//直到现在,珠子还没有相邻的珠子            {
                index[i][j]= s.size();//标记i*n+j+1珠子属于一个新的集合                vector <int> v;
                v.push_back(i*n+j+1);
                s.push_back(v);//为i*n+j+1珠子建立一个新的集合。            }

        }
    }//输出for(vector < vector <int>>::iterator it1= s.begin(); it1!= s.end(); it1++)
    {for(vector <int>::iterator it2= (*it1).begin(); it2!= (*it1).end(); it2++)
        {
            cout < <*it2 < <"";
        }
        cout < < endl;
    }return0;
}

[/Quote]
zhengjiankang 2009-11-30
  • 打赏
  • 举报
回复
有个手机游戏 bubble breaker
做起来跟楼主的要求比较像
我写过那个游戏
做法是对于点击区域的一个球对他的上下左右进行搜索
搜索过的位置标上搜索过的标记
然后对上下左右的4个继续搜索
是一个递归的过程
比如1的右边是1 则继续搜索右边那个1的上下左右
但是这个时候左边那个1已经过了标记 就不用再搜索了

对于楼主的这个题目
可以最这个矩阵的k*k的数据设置上搜索标志和已选入集合标志
从矩阵的第一个数开始搜索
每搜索一个数据周围的数据之后把所有搜索到的数据选入同色相邻集合做上标记

对后面的数据
每次先检查是否已经选入同色相邻元素元素集合的标志
若为真则跳过 假则对元素进行搜索
firanrsm 2009-11-30
  • 打赏
  • 举报
回复
留言是美德
fire_woods 2009-11-30
  • 打赏
  • 举报
回复
连通域标记的时间复杂度是O(N^2)的, 楼主还是把你的代码贴出来看看有没有优化的余地吧.
liao260910 2009-11-29
  • 打赏
  • 举报
回复
刚好我也想找
bawgiitx 2009-11-29
  • 打赏
  • 举报
回复
五行五列,第个球有五种颜色000-100点三位,3*5=15位,long除最高们刚刚好
long []h=long[5];//h[0]表示第一列五个球颜色
long []w=long[5];//w[0]表示第一行五个球颜色
long []rh=long[4];//rh表示第一列与第二列五个球颜色进行异或运算
long []rw=long[4];//rh表示第一行与第二行五个球颜色进行异或运算
结果就在rh,rw 8个数中,然后呢?
yxwlijun 2009-11-28
  • 打赏
  • 举报
回复
受教了,
绿色夹克衫 2009-11-28
  • 打赏
  • 举报
回复
这道题具体怎么通过构造并行来快速求解,我也没想清楚(有可能不是我这种水平能想清楚的),
但可以这么想,比如我把每一种颜色的编号按照001-111(7种)来表示,
那么5个珠子可以用一个15位的2进制来表示,假设该值为n,
那么用n xor (n << 3),此时为0的位,就是前后颜色相等的珠子,
但是为0的判断我还没有想到有什么快速的方法,恐怕需要高手来想了。
如果采用int64的话,可以同时存下21位,也就是说1次位运算同时比较了21个珠子,

行之间的比较也同样可以用位运算来模拟。

[Quote=引用 21 楼 easypal 的回复:]
并行,还没接触过。

用深搜的效率也是N^2,你可以把递归的改成非递归的,时间可能要少一点
[/Quote]
云霄 2009-11-28
  • 打赏
  • 举报
回复
并行,还没接触过。

用深搜的效率也是N^2,你可以把递归的改成非递归的,时间可能要少一点
云霄 2009-11-28
  • 打赏
  • 举报
回复
[Quote=引用 22 楼 litaoye 的回复:]
这道题具体怎么通过构造并行来快速求解,我也没想清楚(有可能不是我这种水平能想清楚的),
但可以这么想,比如我把每一种颜色的编号按照001-111(7种)来表示,
那么5个珠子可以用一个15位的2进制来表示,假设该值为n,
那么用n xor (n < < 3),此时为0的位,就是前后颜色相等的珠子,
但是为0的判断我还没有想到有什么快速的方法,恐怕需要高手来想了。
如果采用int64的话,可以同时存下21位,也就是说1次位运算同时比较了21个珠子,

行之间的比较也同样可以用位运算来模拟。

引用 21 楼 easypal 的回复:
并行,还没接触过。

用深搜的效率也是N^2,你可以把递归的改成非递归的,时间可能要少一点

[/Quote]

经典,原来位运算这么有用
云霄 2009-11-28
  • 打赏
  • 举报
回复
恩,这个程序的分类讨论复杂了,bug多
likee003 2009-11-28
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 easypal 的回复:]
C/C++ code/*
算法思想:
维护一个所有同色相邻珠子集合的容器,和一个标记每个珠子属于哪个集合的二维数组
依次检查每一个珠子,如果与已分配集合的珠子(具体点,就是上方的 和 左边的)颜色相同,就把这个珠子加入到此集合
否则为该珠子分配一个新的集合。
当检查完每个珠子,那么每个珠子都分派到一个集合。

证明:反证
算法结束后,如果存在两个相邻且颜色相同的珠子B,C没有在同一个集合SB中,设?-
[/Quote]

此算法有漏洞,如果它拐几个弯的话,楼主的算法考虑就不全面了。
huqi123456789 2009-11-28
  • 打赏
  • 举报
回复
佩服
whereusejava 2009-11-27
  • 打赏
  • 举报
回复
楼上的已经解决思路还行!
tkminigame 2009-11-27
  • 打赏
  • 举报
回复
没看懂题目是什么意思。
云霄 2009-11-27
  • 打赏
  • 举报
回复
效率O(N^2),够快了吧
云霄 2009-11-27
  • 打赏
  • 举报
回复
上面的代码忘了编译,
下面的代码是编译通过的


/*
算法思想:
维护一个所有同色相邻珠子集合的容器,和一个标记每个珠子属于哪个集合的二维数组
依次检查每一个珠子,如果与已分配集合的珠子(具体点,就是上方的 和 左边的)颜色相同,就把这个珠子加入到此集合
否则为该珠子分配一个新的集合。
当检查完每个珠子,那么每个珠子都分派到一个集合。

证明:反证
算法结束后,如果存在两个相邻且颜色相同的珠子B,C没有在同一个集合SB中,设珠子B在C的左上方。
那么珠子C在B的右下方,并且与B的颜色相同。根据算法结果,C与B在同一个集合中。矛盾产生。
*/


#include <iostream>
#include <vector>
using namespace std;

const int MAXN=5; //矩形的边长

vector< vector<int> > s; //开辟一个vector<vector<int>>类型s容器,用于维护所有的集合;
int index[MAXN][MAXN]; //一个数组Index,保存每个珠子集合的的序号

int color[MAXN][MAXN]; //珠子的颜色数组

int main()
{
int n = MAXN;

//初始化珠子数组的颜色
for(int k=0; k<n; k++)
{
for(int l=0; l<n; l++)
{
color[k][l] = k*l%5;
}
}

//核心代码
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(i-1>=0 &&color[i-1][j]==color[i][j]) //如果此珠子与上方的珠子相同
{
index[i][j] = index[i-1][j]; //标记i*n+j+1珠子与上方的珠子同属于一个集合
s[index[i][j]].push_back(i*n+j+1); //将第i*n+j+1珠子加入所在集合
}
else if(j-1>=0 && color[i][j-1] == color[i][j]) //如果此珠子与左边的珠子相同
{
index[i][j] = index[i][j-1]; //标记i*n+j+1珠子与左边珠子同属于一个集合
s[index[i][j]].push_back(i*n+j+1); //将第i*n+j+1珠子加入所在集合
}
else //直到现在,珠子还没有相邻的珠子
{
index[i][j] = s.size(); //标记i*n+j+1珠子属于一个新的集合
vector<int> v;
v.push_back(i*n+j+1);
s.push_back(v); //为i*n+j+1珠子建立一个新的集合。
}

}
}



//输出
for(vector< vector<int> >::iterator it1= s.begin(); it1 != s.end(); it1++)
{
for(vector<int>::iterator it2= (*it1).begin(); it2 != (*it1).end(); it2++)
{
cout<<*it2<<" ";
}
cout << endl;
}

return 0;
}
云霄 2009-11-27
  • 打赏
  • 举报
回复

/*
算法思想:
维护一个所有同色相邻珠子集合的容器,和一个标记每个珠子属于哪个集合的二维数组
依次检查每一个珠子,如果与已分配集合的珠子(具体点,就是上方的 和 左边的)颜色相同,就把这个珠子加入到此集合
否则为该珠子分配一个新的集合。
当检查完每个珠子,那么每个珠子都分派到一个集合。

证明:反证
算法结束后,如果存在两个相邻且颜色相同的珠子B,C没有在同一个集合SB中,设珠子B在C的左上方。
那么珠子C在B的右下方,并且与B的颜色相同。根据算法结果,C与B在同一个集合中。矛盾产生。
*/


#include <iostream>
#include <string>
using namespace std;

const int MAXN=5; //矩形的边长

vector< vector<int> > s; //开辟一个vector<vector<int>>类型s容器,用于维护所有的集合;
int index[MAXN][MAXN]; //一个数组Index,保存每个珠子集合的的序号

int color[MAXN][MAXN]; //珠子的颜色数组

int main()
{
int n = MAXM;

//初始化珠子数组的颜色
for(int k=0; k<n; k++)
{
for(int l=0; l<n; l++)
{
color[k][l] = k*l%5;
}
}

//核心代码
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(i-1>=0 &&color[i-1][j]==color[i][j]) //如果此珠子与上方的珠子相同
{
index[i][j] = index[i-1][j]; //标记i*n+j+1珠子与上方的珠子同属于一个集合
s[index[i][j]].push_back(i*n+j+1); //将第i*n+j+1珠子加入所在集合
}
else if(j-1>=0 && color[i][j-1] == color[i][j]) //如果此珠子与左边的珠子相同
{
index[i][j] = index[i][j-1]; //标记i*n+j+1珠子与左边珠子同属于一个集合
s[index[i][j]].push_back(i*n+j+1); //将第i*n+j+1珠子加入所在集合
}
else //直到现在,珠子还没有相邻的珠子
{
index[i][j] = s.size(); //标记i*n+j+1珠子属于一个新的集合
vector<int> v;
v.push_back(i*n+j+1);
s.push_back(v); //为i*n+j+1珠子建立一个新的集合。
}

}
}



//输出
for(vector< vector<int> >::iterator it1= s.begin(); it1 != s.end(); it1++)
{
for(vector<int>::iterator it2= (*it1).begin(); it2 != (*it1).end(); it2++)
{
cout<<*it2<<" ";
}
cout << endl;
}

return 0;
}
绿色夹克衫 2009-11-27
  • 打赏
  • 举报
回复
想进一步优化的话,只能依靠构造位运算了!现在并行计算这么火,
很多都要依赖好的位运算。理论上是有可能高于5*5

[Quote=引用 19 楼 coffeegg 的回复:]
可能对于一个程序来说你用o(N^2)能说明问题,但是如果对于一台机器上跑几千个进程来说,这种逐步的优化可以节省不少cpu idle
我现在就卡在这里,能优化一点算一点
主要是不想动硬件了
引用 18 楼 easypal 的回复:
我想O(N^2)应该是最优的时间了,
你不可能不检查每个珠子的颜色就把他归类了吧。

对于常数因子的讨论没多大必要。
就用深搜也挺好的。

[/Quote]
yuandong300 2009-11-27
  • 打赏
  • 举报
回复
好帖子
加载更多回复(13)

33,027

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧