首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 培训 数据库 书店 程序员
中国软件网
欢迎您:游客 | 登录 注册 帮助
  • 渐变色的绳子 [已结贴,结贴人:X_Guan_Guan_H]
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 22:34:13 楼主
    玛丽手中有 n (0 < n < 1024)条渐变色的绳子,她试着将这些绳子连接得更长。玛丽必须将两条绳子相同颜色的一端连接到一起,来保证连接后的绳子也是渐变色的。玛丽有一个愿望:将手中所有的绳子连接为一条渐变色的绳子。请为玛丽制作一个程序,求出她是否可能完成心愿。

    说明:
    玛丽为每个颜色分配了 ID (整数,0 ~ 65535),相同颜色 ID 相同,不同颜色 ID 不同。这样用两个颜色 ID 来表示一条绳子再好不过。

    输入:
    从当前目录 in.txt 文件中读取数据。共 n 行,每行两个十进制整数(以空格间隔),分别代表一条绳子两端颜色的 ID 。

    输出:
        在当前目录生成 out.txt 文件。如果可能,则输出 1 ,不可能则输出 0 。
    输入:
    1 2
    64 64
    2 45
    3 45
    64 45
    45 1

    输出:
    1
    0  修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-25 23:41:391楼 得分:0
    能有什么好一点的算法
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-26 00:13:432楼 得分:0
    欧拉路的问题,一行数据是一条线,数为顶点。为1的判定依据,图是连通图,且有0个或两个奇数度结点。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-26 02:06:593楼 得分:0
    引用 2 楼 bottlebox 的回复:
    欧拉路的问题,一行数据是一条线,数为顶点。为1的判定依据,图是连通图,且有0个或两个奇数度结点。


    还要考虑这个图是怎么构成的啊
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-26 14:34:354楼 得分:0
    最简单的方法:n对数的全排列n!种,逐一测试,n在13以内基本没有问题。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-27 01:09:545楼 得分:0
    尝试写了一下,不知道还有没更好的解法
    C/C++ code
    #include <fstream> #include <vector> #include <assert.h> #include <windows.h> using namespace std; unsigned short PointTable[65536]={0};//顶点出现次数表 int _tmain(int argc, _TCHAR* argv[]) { int line[1024][2]; ifstream in("in.txt"); assert(in); int nLen=0;//绳子数 int nPtnum=0;//不同的顶点数 int nOdd=0;//奇顶点数 vector<POINT> lineSet; int result=0; while(!in.eof()) { POINT pt; in>>pt.x; if(in>>pt.y){ lineSet.push_back(pt); ++PointTable[pt.x]; if(PointTable[pt.x]%2==1)//为奇数 nOdd++; else nOdd--; ++PointTable[pt.y]; if(PointTable[pt.y]%2==1) nOdd++; else nOdd--; } } //连通性判断 vector<int> PointSet; PointSet.push_back(lineSet[0].x); PointTable[lineSet[0].x]=0; if(lineSet[0].x!=lineSet[0].y){ PointSet.push_back(lineSet[0].y); PointTable[lineSet[0].y]=0; } lineSet.erase(lineSet.begin()); while(PointSet.size()){ for(int i=0;i<lineSet.size();i++){ if(lineSet[i].x==PointSet[0]){//两线相连 if(PointTable[lineSet[i].y]){//本顶点未出现过 PointSet.push_back(lineSet[i].y);//加入搜索集 PointTable[lineSet[i].y]=0; } lineSet.erase(lineSet.begin()+i);//排除该线 i--;//正确转下一条线 } else if(lineSet[i].y==PointSet[0]){//两线相连 if(PointTable[lineSet[i].x]){//本顶点未出现过 PointSet.push_back(lineSet[i].x);//加入搜索集 PointTable[lineSet[i].x]=0; } lineSet.erase(lineSet.begin()+i);//排除该线 i--;// } } PointSet.erase(PointSet.begin()); } if(lineSet.size()==0//是连通图 &&(nOdd==0||nOdd==2)) result=1; printf("结果为%d",result); return 0; }
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-27 17:30:306楼 得分:0
    我觉得可以这样:
    对于两边 ID 一样的绳子,不能自己连自己。(即需要连别的绳子)其他情况下,只要考虑个数为奇数的 ID 不超过2个。

    C/C++ code
    #include <fstream> using std::ifstream; using std::ofstream; const size_t N = 65536; const char* in_file = "in.txt"; const char* out_file = "out.txt"; struct id { bool same_; unsigned int cnt_; }; int main() { id ids[N] = {}; ifstream in(in_file); int x, y; while (in >> x >> y) { if (x == y) { if (ids[x].cnt_ == 0) ids[x].same_ = true; // omitted: lines[x].cnt_ += 2; } else { ids[x].same_ = false; ids[x].cnt_++; ids[y].same_ = false; ids[y].cnt_++; } } int odd_cnt = 0; const int TOO_MANY_ODD = 3; for (size_t i = 0; i < N; ++i) { if (ids[i].same_) { odd_cnt += TOO_MANY_ODD; // s.t. failed break; } odd_cnt += ids[i].cnt_ & 1; } ofstream out(out_file); out << (odd_cnt >= TOO_MANY_ODD ? 0 : 1); }
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-27 21:12:567楼 得分:0
    引用 6 楼 Vitin 的回复:
    我觉得可以这样:
    对于两边 ID 一样的绳子,不能自己连自己。(即需要连别的绳子)其他情况下,只要考虑个数为奇数的 ID 不超过2个。

    应该要考虑连通性的,比如上面的数据再加入
    7 5
    5 6
    6 7
    你的程序就错了
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-28 10:39:008楼 得分:0
    很简单,每个颜色为点,绳子为边,就是一个欧拉回路问题。
    所以判断法则就是
    i)判断图是否连通,不连通失败
    ii)判断奇数度数点的数目,数目大于2那么也失败
    余下均成功
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-28 11:00:349楼 得分:0
    是的,呵呵,6楼错了。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-28 11:34:4710楼 得分:0
    这题有一个很特殊的问题你们没考虑清楚,我还没想周全解决方法,饭后揭晓!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-28 11:37:2211楼 得分:0
    想到一个判断连通性的高效方法,复杂度是O(L),供参考。

    C/C++ code
    #include <fstream> #include <algorithm> using std::ifstream; using std::ofstream; using std::max; using std::min; const size_t N = 65536; const size_t L = 1024; const char* in_file = "in.txt"; const char* out_file = "out.txt"; struct line { size_t no_; }; struct id { size_t line_no_; unsigned int cnt_; }; int main() { id ids[N] = {}; line lines[L] = {}; int odd_cnt = 0; size_t line_no = 0; ifstream in(in_file); size_t x, y; while (in >> x >> y) { // 连通性,lines记录线与线的连通关系 if (ids[x].cnt_ * ids[y].cnt_) { if (lines[ids[x].line_no_].no_ > lines[ids[y].line_no_].no_) { lines[ids[x].line_no_].no_ = lines[ids[y].line_no_].no_; } else if (lines[ids[x].line_no_].no_ < lines[ids[y].line_no_].no_) { lines[ids[y].line_no_].no_ = lines[ids[x].line_no_].no_; } } else if (ids[x].cnt_) { ids[y].line_no_ = ids[x].line_no_; } else if (ids[y].cnt_) { ids[x].line_no_ = ids[y].line_no_; } else { ids[x].line_no_ = line_no; ids[y].line_no_ = line_no; lines[line_no].no_ = line_no; ++line_no; } // 奇数度统计,使用5楼的快速算法 ++ids[x].cnt_; (ids[x].cnt_ % 1) ? ++odd_cnt : --odd_cnt; ++ids[y].cnt_; (ids[y].cnt_ % 1) ? ++odd_cnt : --odd_cnt; } const int TOO_MANY_ODD = 3; bool result = odd_cnt < TOO_MANY_ODD; if (result) for (size_t i = 1; i < line_no; ++i) if (lines[i].no_ == i) // 不连通 { result = false; break; } ofstream out(out_file); out << (result ? 1 : 0); }
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-28 11:59:2512楼 得分:0
    恩,11楼的代码有一个Bug,修改一下。

    C/C++ code
    #include <fstream> using std::ifstream; using std::ofstream; const size_t N = 65536; const size_t L = 1024; const char* in_file = "in.txt"; const char* out_file = "out.txt"; struct line { size_t no_; }; struct id { size_t line_no_; unsigned int cnt_; }; int main() { id ids[N] = {}; line lines[L] = {}; int odd_cnt = 0; size_t line_no = 0; ifstream in(in_file); size_t x, y; while (in >> x >> y) { // 连通性,lines记录线与线的连通关系 if (ids[x].cnt_ * ids[y].cnt_) { if (lines[ids[x].line_no_].no_ > lines[ids[y].line_no_].no_) { lines[lines[ids[x].line_no_].no_].no_ = lines[ids[y].line_no_].no_; // 修改 } else if (lines[ids[x].line_no_].no_ < lines[ids[y].line_no_].no_) { lines[lines[ids[y].line_no_].no_].no_ = lines[ids[x].line_no_].no_; // 修改 } } else if (ids[x].cnt_) { ids[y].line_no_ = ids[x].line_no_; } else if (ids[y].cnt_) { ids[x].line_no_ = ids[y].line_no_; } else { ids[x].line_no_ = line_no; ids[y].line_no_ = line_no; lines[line_no].no_ = line_no; ++line_no; } // 奇数度统计,使用5楼的快速算法 ++ids[x].cnt_; (ids[x].cnt_ % 1) ? ++odd_cnt : --odd_cnt; ++ids[y].cnt_; (ids[y].cnt_ % 1) ? ++odd_cnt : --odd_cnt; } const int TOO_MANY_ODD = 3; bool result = odd_cnt < TOO_MANY_ODD; if (result) for (size_t i = 1; i < line_no; ++i) if (lines[i].no_ == i) // 不连通 { result = false; break; } ofstream out(out_file); out << (result ? 1 : 0); }
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-28 12:40:5713楼 得分:0
    晕了,还是错的。
    又修改了一下,但是现在复杂度已经和5楼一样了,呵呵。
    C/C++ code
    #include <fstream> using std::ifstream; using std::ofstream; const size_t N = 65536; const size_t L = 1024; const char* in_file = "in.txt"; const char* out_file = "out.txt"; struct line { size_t no_; }; struct id { size_t line_no_; unsigned int cnt_; }; int main() { id ids[N] = {}; line lines[L] = {}; int odd_cnt = 0; size_t line_no = 0; ifstream in(in_file); size_t x, y; while (in >> x >> y) { // 连通性,lines记录线与线的连通关系 if (ids[x].cnt_ * ids[y].cnt_) { // 重大的修改 size_t x_no = ids[x].line_no_; size_t y_no = ids[y].line_no_; while (lines[x_no].no_ != lines[y_no].no_) { if (lines[x_no].no_ < lines[y_no].no_) { size_t tmp = lines[y_no].no_; lines[y_no].no_ = lines[x_no].no_; y_no = tmp; } else { size_t tmp = lines[x_no].no_; lines[x_no].no_ = lines[y_no].no_; x_no = tmp; } } } else if (ids[x].cnt_) { ids[y].line_no_ = ids[x].line_no_; } else if (ids[y].cnt_) { ids[x].line_no_ = ids[y].line_no_; } else { ids[x].line_no_ = line_no; ids[y].line_no_ = line_no; lines[line_no].no_ = line_no; ++line_no; } // 奇数度统计,使用5楼的快速算法 ++ids[x].cnt_; (ids[x].cnt_ % 1) ? ++odd_cnt : --odd_cnt; ++ids[y].cnt_; (ids[y].cnt_ % 1) ? ++odd_cnt : --odd_cnt; } const int TOO_MANY_ODD = 3; bool result = odd_cnt < TOO_MANY_ODD; if (result) for (size_t i = 1; i < line_no; ++i) if (lines[i].no_ == i) // 不连通 { result = false; break; } ofstream out(out_file); out << (result ? 1 : 0); }
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-28 13:48:3314楼 得分:0
    引用 12 楼 Vitin 的回复:
    恩,11楼的代码有一个Bug,修改一下。

    这个算法思路不错,我简化了一下,看看有没问题
    C/C++ code
    if (ids[x].cnt_ * ids[y].cnt_)//两个点都存在 { if(ids[x].line_no_>ids[y].line_no_){//两顶点不在同一条线的集,取小线号的集 ids[x].line_no_=ids[y].line_no_; line_no--; } } 。。。。。。 bool result = odd_cnt < TOO_MANY_ODD&&line_no==1;
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-28 13:53:1415楼 得分:0
    上面少了一个判断
    C/C++ code
    if (ids[x].cnt_ * ids[y].cnt_)//两个点都存在 { if(ids[x].line_no_>ids[y].line_no_)//两顶点不在同一条线的集,取小线号的集 ids[x].line_no_=ids[y].line_no_; else ids[y].line_no_=ids[x].line_no_; line_no--; }
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-28 14:10:4216楼 得分:0
    我觉得不能这样简化,因为12楼的代码本身错了。修改后的代码见13楼。
    如果修改点所在的线的集合,应该修改该集合的所有的点,而不是仅仅一个点。

    所以我建立了两重关系,点与线的关系,以及线与线的关系。
    后者是一些树,根为最小编号的线。如果两棵树有连接,就将它们合并为一棵树。
    最后,如果只剩下一棵树(根为0的树),就成功了。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-06-28 14:35:5017楼 得分:0
    上面改确实有问题,改用指针应该能解决
    C/C++ code
    #include <fstream> using std::ifstream; using std::ofstream; const size_t N = 65536; const size_t L = 1024; const char* in_file = "in.txt"; const char* out_file = "out.txt"; struct id { size_t* line_no_;//点所属线集的地址 unsigned int cnt_;//点出现的次数 }; int main() { id ids[N] = {};//点集 size_t lines[L] = {};//线集 int odd_cnt = 0; int line_no=0; //线集的序号 int nLine=0;//实际线集数 ifstream in(in_file); size_t x, y; while (in >> x >> y) { // 连通性,lines记录线与线的连通关系 if (ids[x].cnt_ * ids[y].cnt_)//两个点都存在 { if(*(ids[x].line_no_)>*(ids[y].line_no_)){//两顶点不在同一条线的集,取小线号的集 *(ids[x].line_no_)=*(ids[y].line_no_); nLine--; } else if(*(ids[x].line_no_)<*(ids[y].line_no_)){ *(ids[y].line_no_)=*(ids[x].line_no_); nLine--; } } else if (ids[x].cnt_)//只有前点存在 { ids[y].line_no_ = ids[x].line_no_; } else if (ids[y].cnt_)//只有后点存在 { ids[x].line_no_ = ids[y].line_no_; } else//两个点都不存在 { ids[x].line_no_ = &lines[line_no]; ids[y].line_no_ = &lines[line_no]; lines[line_no]= line_no; ++line_no; nLine++; } // 奇数度统计,使用5楼的快速算法 ++ids[x].cnt_; (ids[x].cnt_ % 1) ? ++odd_cnt : --odd_cnt; ++ids[y].cnt_; (ids[y].cnt_ % 1) ? ++odd_cnt : --odd_cnt; } cons