• UVA


    //法1:先模拟操作,算出最后的电子表格,接着在每次查询时直接在电子表格中,找到所求的单元格
    /*
      此方法最关键的地方,应是怎样建立原来的位置和后来的位置的联系
      
      入门经典的法一,很巧妙地借助了这样的数组定义;
      d[i][j] = i*BIG + j,记录下了原来的位置...在后面的插入、删除和交换等等步骤之后
      虽然d[i][j]里装的数字可能变化了,可是只要计算 d[i][j] / BIG, d[i][j] % BIG,得到的就是这个位置的初始位置的行数和列数了
      
      以及,填充ans数组时,相当于遍历每个位置,每个位置(i,j)会有一个对应的数字 i * BIG +j,我们可以找到它原来的行列位置,作为ans[i][j]中的i,j(怎么找呢,当然是用d数组里的值整除BIG和取模BIG啦~),因此有 ans[d[i][j] / BIG][d[i][j] % BIG] = i * BIG + j;
      
      它的含义是:原来第i行第j列的数字,现在放到了新的位置,而我如果想知道这个新的位置,只要将 (i * BIG + j) 整除BIG和取模BIG即可
      
      所以,如果填充ans数组时,遇到了原来存在但现在被删掉了的数字,那么原来的行数和列数,一定不会作为ans[i][j]中的i和j,因为既然删除,最初的那个d[i][j]肯定也就被删掉了
      
      如果填充ans数组时,遇到了新加上的数,那么它之前肯定没被填充到d数组,而全局数组d,没被填充的部分就是0,所以,它根本不会影响ans数组的正常填充
      
      总之,这题很巧妙地借助了取模和整除,建立了原来的位置和现在的位置之间的关系,以及表示位置的 i*BIG + j,入门经典中指定的BIG是10000,但其实100就够了,它的目的只是让i被分离出来时,一定不会受到j进位的影响,既然i,j都是最大50,也就是最多2位,BIG用100也就够了
      
      BTW,这题和 HDU - 6098 Inversion 其实有些异曲同工之妙,虽然看上去很不同,但它们都有一个共同点,都要和最初的标号(或是位置)建立上联系,对这题的这种方法,是利用乘法+加法、除法+取模,来将原来的位置和现在的位置建立联系(它们之间有个不会变化的纽带,就是构造出的那个数字,d[i][j] / BIG, d[i][j] % BIG,于是这就保证了,对于某个位置而言,只要它没被删除,无论它移动到那里,在别的位置上,仍然可以通过构造出的那个数字,整除和取模得到原先的位置)
      
      这种思路实在是精妙,让人想对刘汝佳前辈伏地膜...
      
      而hdu那题,是通过构造结构体,将序号和数值绑定起来
      (没记错的话,这道题我已经在我的blog上发了题解啦,需要的不妨看看)
      
      两题的共性就是:都要用一些特定方法或思路,来保证一个不变量,作为最初和最终状态的纽带
      
    */


    #include <iostream>
    #include <cstring>
    using namespace std;
    const int maxd = 100;
    const int BIG = 100;
    int r, c, n, d[maxd][maxd], d2[maxd][maxd], ans[maxd][maxd], cols[maxd];
    /*依次表示:行、列、操作次数
    d:将d中的值按照最初位置构造 i * BIG + j并赋值,d中的值会改变位置,但通过值仍能推出初始位置(除非删除)
    d2:起临时变量作用的数组,方便进行系列操作
    ans:下标对应初始位置,值对应最终位置的构造值 i * BIG + j,整除取模可得最终位置
    cols:表示每次插入或删除操作波及的行数或列数,因而每次操作前需清空
    */
    
    void copy(char type, int p, int q)
    {
    	if (type == 'R')
    	{
    		for (int i = 1; i <= c; i++)
    		d[p][i] = d2[q][i];
    	}
    	else
    	{
    		for (int i = 1; i <= r; i++)
    		d[i][p] = d2[i][q];
    	}
    }
    
    void del(char type)
    {
    	memcpy(d2, d, sizeof(d));
    	int cnt = type == 'R' ? r : c, cnt2 = 0;
    	for (int i = 1; i <= cnt; i++)
    	{
    		if (!cols[i]) copy(type, ++cnt2, i);
    	}
    	if (type == 'R') r = cnt2; else c = cnt2;
    }
    
    void ins(char type)
    {
    	memcpy(d2, d, sizeof(d));
    	int cnt = type == 'R' ? r : c, cnt2 = 0;
    	for (int i = 1; i <= cnt; i++)
    	{
    		if (cols[i]) copy(type, ++cnt2, 0);
    		copy(type, ++cnt2, i);
    	}
    	if (type == 'R') r = cnt2; else c = cnt2;
    }
    
    int main()
    {
    	int r1, c1, r2, c2, q, kase = 0;
    	char cmd[10];
    	memset(d, 0, sizeof(d));
    	while (cin >> r >> c >> n && r)
    	{
    		int r0 = r, c0 = c;
    		for (int i = 1; i <= r; i++)
    		for (int j = 1; j <= c; j++)
    		d[i][j] = i * BIG + j;
    		
    		while (n--)
    		{
    			cin >> cmd;
    			if (cmd[0] == 'E')
    			{
    				cin >> r1 >> c1 >> r2 >> c2;
    				swap(d[r1][c1], d[r2][c2]);
    			}
    			else
    			{
    				int a, x;
    				cin >> a;
    				memset(cols, 0, sizeof(cols));
    				for (int i = 0; i < a; i++)
    				{
    					cin >> x;
    					cols[x] = 1;
    				}
    				if (cmd[0] == 'D') del(cmd[1]);
    				else ins(cmd[1]);
    			}
    		}
    		memset(ans, 0, sizeof(ans));
    		for (int i = 1; i <= r; i++)
    		for (int j = 1; j <= c; j++)
    		{
    			ans[d[i][j] / BIG][d[i][j] % BIG] = i * BIG + j;
    		}
    		if (kase) cout << endl;
    		cout << "Spreadsheet #" << ++kase << endl;
    		cin >> q;
    		while (q--)
    		{
    			cin >> r1 >> c1;
    			cout << "Cell data in (" << r1 << "," << c1 << ") ";
    			if (ans[r1][c1] == 0) cout << "GONE" << endl;
    			else cout << "moved to (" << ans[r1][c1] / BIG << "," << ans[r1][c1] % BIG << ")" << endl;
    		}
    	}
    	return 0;
    }

    //法二:先将所有的操作保存,然后对于每个查询重新执行每个操作,但不需要计算整个电子表格的变化,而只关注所查询的单元格的位置变化。对于题目给定的规模来说,这个方法不仅更好写,而且效率更高
    //入门经典的法二,代码就比较容易理解了,逻辑十分清楚

    #include <iostream>
    #include <cstring>
    using namespace std;
    typedef pair<int, int> p;
    const int maxd = 10000;
    
    struct Command
    {
    	char c[5];
    	p pos1, pos2; //position 1, position 2
    	int a, x[20];
    }cmd[maxd];
    
    int r, c, n;
    
    int simulate(int &r0, int &c0)
    {
    	for (int i = 0; i < n; i++)
    	{
    		if (cmd[i].c[0] == 'E')
    		{
    			p pos3(r0, c0);
    			if (cmd[i].pos1 == pos3)
    			{
    				r0 = cmd[i].pos2.first;
    				c0 = cmd[i].pos2.second;
    			}
    			else if (cmd[i].pos2 == pos3)
    			{
    				r0 = cmd[i].pos1.first;
    				c0 = cmd[i].pos1.second;
    			}
    		}
    		else
    		{
    			int dr = 0, dc = 0;
    			for (int j = 0; j < cmd[i].a; j++)
    			{
    				int x = cmd[i].x[j];
    				if (cmd[i].c[0] == 'I')
    				{
    					if (cmd[i].c[1] == 'R' && x <= r0) dr++;
    					else if (cmd[i].c[1] == 'C' && x <= c0) dc++;
    				}
    				else
    				{
    					if (cmd[i].c[1] == 'R') 
    					{
    						if (x == r0) return 0;
    						if (x < r0) dr--;
    					}
    					else
    					{
    						if (x == c0) return 0;
    						if (x < c0) dc--;
    					}
    				}
    			}
    			r0 += dr; c0 += dc;
    		}
    	}
    	return 1;
    }
    int main()
    {
    	int r0, c0, q, kase = 0;
    	while (cin >> r >> c >> n && r)
    	{
    		for (int i = 0; i < n; i++)
    		{
    			cin >> cmd[i].c;
    			if (cmd[i].c[0] == 'E') cin >> cmd[i].pos1.first >> cmd[i].pos1.second >>  cmd[i].pos2.first >> cmd[i].pos2.second;
    			else
    			{
    				cin >> cmd[i].a;
    				for (int j = 0; j < cmd[i].a; j++)
    				cin >> cmd[i].x[j];
    			}
    		}
    		if (kase) cout << endl;
    		cout << "Spreadsheet #" << ++kase << endl;
    		
    		cin >> q;
    		while (q--)
    		{
    			cin >> r0 >> c0;
    			cout << "Cell data in (" << r0 << "," << c0 << ") ";
    			if (!simulate(r0, c0)) cout << "GONE" << endl;
    			else cout << "moved to (" << r0 << "," << c0 << ")" << endl;
    		}
    	}
    	return 0;
    }


  • 相关阅读:
    OpenCV 轮廓填充drawContours函数解析
    C++ MultiByteToWideChar和WideCharToMultiByte用法详解
    删除后缀dll文件,无需下载软件
    MYSQL误删除DELETE数据找回
    神经网络减少GPU显存占用的技术
    keras tensorflow 获取某层输出和层内参数的值
    聚光灯矩阵
    tf.linalg.band_part 和 tf.matrix_band_part
    机器学习,BootStrap
    极大团算法思路小记
  • 原文地址:https://www.cnblogs.com/mofushaohua/p/7789533.html
Copyright © 2020-2023  润新知