根据http://hi.baidu.com/algorithm/item/d51b15f7a8ea1c0a84d278be这个开始练习ac,刚开始接触这道题时以为是道搜索题,读完之后深思了一下,感觉不需要套用一贯的dfs或者bfs,直接根据自己的思路走,然后注意一下效率问题就行了!可见算法注重灵活,而不是一贯的套用现有的模式。

利用题中示例:

簇号from[]:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
     目前簇中内容应该在的簇号to[]:0 1 2 0 7 0 5 0 0   8   3   4    0   0    0   0   0    6   0   0

很自然的想法就是同时遍历from和to数组,如果from和to中内容相同,说明当前簇中内容不需要移动,否则为了优化必须进行移动,但是可以移动的前提是to所指的簇中内容为空,即from[to[i]]=0。可以先把满足移动条件的进行移动,由于移动之后,可能会引起其它簇满足移动条件,所以还需要再次遍历from和to,直到没有满足移动的簇。这个时候,有两种情况,一是达到优化状态,即from=to;另外一种是存在一个环,就如题中的5-7,7-5。针对第二种情况就是打破环,然后再次对满足移动条件的簇进行移动。多个嵌套循环就能解决了,但是这个过程使得需要多次遍历才能把所有满足移动条件的簇操作完全(由于移动导致了其他一些簇满足了移动条件后,需要第二次遍历才能将这些簇进行移动)。很明显会超时的。

有没有可能使得一次遍历之后,就能把不属于环的一些簇全部移动到位呢?答案是肯定的。

看下面代码,opt[]指在优化之后,簇i存放的是原来的簇opt[i]的内容。

#include <iostream>
#include <vector>
using namespace std;
int n, k;
vector<int> opt ;
vector<int> c2f;
int count;
bool moved = false;
void MoveBeginAt(int pos)
{
while( opt[pos] != 0 && !c2f[pos] )
{
int from = opt[pos];
int to = pos;
cout << from << " " << to << endl;
moved = true;
c2f[to] = c2f[from];
c2f[from] = 0;
opt[pos] = pos;
pos = from;
}
}
int MaxFreeIndex()
{
int i = c2f.size();
while( c2f[--i] );
return i;
}
int main()
{
while( cin >> n >> k )
{
opt.assign(n+1, 0);
c2f.assign(n+1, 0);
count = 0;
moved = false;
for(int i = 0; i < k; ++i)
{
int m; cin >> m;
for(int j = 0; j < m; ++j)
{
int c;
cin >> c;
opt[++count] = c;
c2f[c] = i + 1;
}
}
for(int i = 1; i <= count; ++i)
if( !c2f[i] )
MoveBeginAt( i );
int from = 0 ;
for(int i = 1; i <= count; ++i)
{
if( opt[i] != i )
{
if( !from )
from = i;
else if( opt[i] == from )
{
int to = MaxFreeIndex();
cout << from << " " << to << endl;
opt[i] = to;
c2f[to] = c2f[from];
c2f[from] = 0;
MoveBeginAt( from );
i = from ;
from = 0;
}
}
}
cout << (moved?"":"No optimization needed\n") ;
}
return 0;
}

另外还有一种利用栈的解法,也很巧妙,思路见 http://www.cnblogs.com/damacheng/archive/2010/09/24/1833983.html;代码实现如下:

#include <iostream>
#include <stack>
#include <vector>
using namespace std;
int n, k;
vector<int> opt;
stack<int> s;
int count ;
int MaxFreeIndex()
{
int i = opt.size() - 1;
while( opt[i] )
--i;
return i;
}
void Work()
{
bool moved = false;
for(int i = 1; i < opt.size(); ++i){
if( opt[i] && opt[i] != i ){
moved = true;
s.push( i );
int b = i, cur = opt[i];
while( true ){
s.push( cur );
if( !opt[cur] )
break;
else if( opt[cur] == b ){
int j = MaxFreeIndex();
cout << cur << " " << j << endl;
opt[j] = b;
opt[cur] = 0;
break;
}
cur = opt[cur];
}
int from, to = s.top();
s.pop();
while( !s.empty() ){
from = s.top();
cout << from << " " << to << endl;
opt[to] = opt[from];
to = s.top();
s.pop();
}
opt[to] = 0;
}
}
cout << (moved?"":"No optimization needed\n") ;
}
int main()
{
while( cin >> n >> k ){
opt.assign( n + 1, 0 );
count = 0;
for(int i = 0; i < k; ++i){
int m;
cin >> m;
for(int j = 0; j < m; ++j){
int c;
cin >> c;
opt[c] = ++count;
}
}
Work();
}
return 0;
}

POJ 1033 Defragment的更多相关文章

  1. POJ题目排序的Java程序

    POJ 排序的思想就是根据选取范围的题目的totalSubmittedNumber和totalAcceptedNumber计算一个avgAcceptRate. 每一道题都有一个value,value ...

  2. 【动态规划】POJ 1161 & ZOJ1463 & XMU 1033 Brackets sequence

    题目链接: http://acm.xmu.edu.cn/JudgeOnline/problem.php?id=1033 http://poj.org/problem?id=1141 ZOJ目前挂了. ...

  3. POJ1033 Defragment

    题目来源:http://poj.org/problem?id=1033 题目大意: 某操作系统的文件系统中,所有的磁盘空间被分为N个大小相等的cluster,编号1至N.每个文件占用一个或多个clus ...

  4. [ACM训练] 算法初级 之 搜索算法 之 广度优先算法BFS (POJ 3278+1426+3126+3087+3414)

    BFS算法与树的层次遍历很像,具有明显的层次性,一般都是使用队列来实现的!!! 常用步骤: 1.设置访问标记int visited[N],要覆盖所有的可能访问数据个数,这里设置成int而不是bool, ...

  5. POJ推荐50题

    此文来自北京邮电大学ACM-ICPC集训队 此50题在本博客均有代码,可以在左侧的搜索框中搜索题号查看代码. 以下是原文: POJ推荐50题1.标记“难”和“稍难”的题目可以看看,思考一下,不做要求, ...

  6. 双向广搜 POJ 3126 Prime Path

      POJ 3126  Prime Path Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 16204   Accepted ...

  7. POJ 3126 Prime Path (BFS)

    [题目链接]click here~~ [题目大意]给你n,m各自是素数,求由n到m变化的步骤数,规定每一步仅仅能改变个十百千一位的数,且变化得到的每个数也为素数 [解题思路]和poj 3278类似.b ...

  8. POJ题目细究

    acm之pku题目分类 对ACM有兴趣的同学们可以看看 DP:  1011   NTA                 简单题  1013   Great Equipment     简单题  102 ...

  9. poj 3126 Prime Path bfs

    题目链接:http://poj.org/problem?id=3126 Prime Path Time Limit: 1000MS   Memory Limit: 65536K Total Submi ...

随机推荐

  1. 安装Codeception框架

    安装Codeception框架 打开终端,进入项目根目录: composer require "codeception/codeception:*" 安装完成,在vendor目录会 ...

  2. Oracle并行查询出错

    1.错误描写叙述 ORA-12801: 并行查询服务器P007中发出错误信号 ORA-01722:无效数字 12801.00000 -"error signaled in parallel ...

  3. ASP.NET MVC局部视图

    使用ASP.NET MVC局部视图避免JS拼接HTML,编写易于维护的HTML页面   以前使用ASP.NET WebForm开发时,喜欢使用Repeater控件嵌套的方式开发前台页面,这样就不用JS ...

  4. Android Studio如何设置自己主动提示代码

    同Eclipse时间,您可以设置,无论你是设置输入不管什么信,可以提示码,在Android Studio也可以 设置.并且比Eclipse设置来的简单. 当然假设你认为代码自己主动提示会减少你的代码水 ...

  5. 最受欢迎web前端技术总结

    Web前端技术发展非常快,主流技术的进步.想想刚毕业那会用asp技术.目前,该网站已经非常少见主流应用. 后来的后来J2EE框架.然后SpringMVC声望,然而,最近的各种js框架广泛传播,Html ...

  6. js面向对象学习总结

    1.函数作为参数进行传递 function a(str,fun){ console.log(fun(str)) }; function up(str){ return str.toUpperCase( ...

  7. SSIS如何引用外部DLL

    原文:SSIS如何引用外部DLL 当SSIS引用外部的DLL时,外部的DLL须满足以下条件: 1. DLL是强命名. 2. 加入到GAC (C:\WINDOWS\assembly),直接把DLL拉进目 ...

  8. Linux根目录下文件说明

    /bin:存放最常用命令: /boot:启动Linux的核心文件: /dev:设备文件: /etc:存放各种配置文件: /home:用户主目录: /lib:系统最基本的动态链接共享库: /mnt:一般 ...

  9. [转]SQL2005后的ROW_NUMBER()函数的应用

    SQL Server 2005后之后,引入了row_number()函数,row_number()函数的分组排序功能使这种操作变得非常简单 分组取TOP数据是T-SQL中的常用查询, 如学生信息管理系 ...

  10. Toast,AlertDialog的误解

    在一般的软件开发中,子线程中是不能更改UI主线程中创建的UI控件的.之前的理解是Toast也不能在子线程中创建.事实上并不是这样子的. @Override protected void onCreat ...