UVa512
参考书籍《算法竞赛入门经典》(第二版)
?
?思路一:先模拟操作,算出最后的电子表格,讲原始位置的值存在数组中,经过交换,插入,删除等操作后,在操作后的数组下标与数组当中所存在的值(0和原始位置)来查找存在与否或者移动后的位置。
?
#include <stdio.h>
#include <string.h>
#define maxd 100
#define BIG 10000
int r, c, n, d[maxd][maxd], d2[maxd][maxd], ans[maxd][maxd], cols[maxd];
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)//type即为传进来的cmd[1]-->对行或者列操作
{
memcpy(d2, d, sizeof(d));//将可能已经处理的d数组复制给d2数组
int cnt = (type == 'R' ? r : c);//赋值给cnt d数组对应的行数或者列数(取决于type)
int cnt2 = 0;
for (int i = 1; i <= cnt; i++)//赋值给cnt d数组对应的行数或者列数(取决于type)
{
if (!cols[i])//由已经置为1的数组来判断操作,将没有置为1的行或者列重新排序
copy(type, ++cnt2, i);//拷贝,注意++cnt2,即为从1开始
}
if (type == 'R')//更新行数或者列数,更新为执行指令后的值
r = cnt2;
else
c = cnt2;
}
//插入函数
void ins(char type)//type即为传进来的cmd[1]-- > 对行或者列操作
{
memcpy(d2, d, sizeof(d));//将可能已经处理的d数组复制给d2数组
int cnt = (type == 'R' ? r : c);//赋值给cnt d数组对应的行数或者列数(取决于type)
int cnt2 = 0;
for (int i = 1; i <= cnt; i++)//赋值给cnt d数组对应的行数或者列数(取决于type)
{
if (cols[i])//由已经置为1的数组来判断操作,插入将置为1的行或者列,并数组整体重排
copy(type, ++cnt2, 0);//插入,插入值为0,因为数组d/d2上的0行0列都是0,所以可以拷贝0行0列的数值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));//将数组d归零
while (scanf("%d%d%d", &r, &c, &n) == 3 && r)//输入单元格的行与列,n代表指令执行的次数,并且上r是因为不能是0行0列;输入0 0退出
{
int r0 = r, c0 = c;
for (int i = 1; i <= r; i++)//对数组赋值注意是从[1][1]开始的以0为行和以0为列不用,这样是方便对应各中的行列序号
{
for (int j = 1; j <= c; j++)
{
d[i][j] = i * BIG + j;//这里的赋值i * BIG + j是为了记录原始位置
}
}
while (n--)//指令执行
{
scanf("%s", cmd);//输入指令
if (cmd[0] == 'E')//进入交换指令
{
scanf("%d%d%d%d", &r1, &c1, &r2, &c2);//输入交换的两个坐标
//交换
int t = d[r1][c1];
d[r1][c1] = d[r2][c2];
d[r2][c2] = t;
}
else//进入删除和插入指令
{
int a, x;
scanf("%d", &a);//a为需要删除或插入的 行的次数或者列的次数
memset(cols, 0, sizeof(cols));//cols数组就是需要交换的行或者列,置0
for (int i = 0; i < a; i++)
{
scanf("%d", &x);//输入删除或者插入的行或者列
cols[x] = 1;//置为1,作为标记
}
//指令执行
if (cmd[0] == 'D')//进入删除函数-->“D”
del(cmd[1]);//指令数组的第二位是区别操作对象行与列的-->“R”/ “C”
else //进入插入函数-->“I”
ins(cmd[1]);//指令数组的第二位是区别操作对象行与列的-->“R”/ “C”
}
}
//以上操作目的是为了得到 数组d, r, c 更新后的状态
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;//ans[原始对应行坐标][原始对应列坐标] = 现在重排后的的坐标,没有赋值的即为0,不存在了
}
}
if (kase > 0)//第一次kase为0,后面每次输出换行
printf("\n");
printf("Spreadsheet #%d\n", ++kase);//多次输出的提示
scanf("%d", &q);//q代表需要查看坐标的次数
while (q--)
{
scanf("%d%d", &r1, &c1);
printf("Cell data in (%d,%d)", r1, c1);
if (ans[r1][c1] == 0)
printf("GONE\n");//不存在了,因为置为0了
else
printf("moved to (%d %d)\n", ans[r1][c1] / BIG, ans[r1][c1] % BIG);
}
}
return 0;
}
思路二:创建结构体,把每组模拟执行的操作信息放在一个结构体中,当查询时再进行每个操作,不需要将整个表的变化进行计算,只需要关注所查询的单元格的位置变化。
#include <stdio.h>
#include <string.h>
#define maxd 10000
struct Command
{
char c[5];//操作模式
int r1, c1, r2, c2;//要交换的两个值
int a, x[20];//a是插入或者删除的行或列数,x[i]是操作的行列序号
}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')//交换
{
//如果要查找的数与交换的数无关,就没必要交换了
if (cmd[i].r1 == *r0 && cmd[i].c1 == *c0)
{
*r0 = cmd[i].r2;
*c0 = cmd[i].c2;
}
else if (cmd[i].r2 == *r0 && cmd[i].c2 == *c0)
{
*r0 = cmd[i].r1;
*c0 = cmd[i].c1;
}
}
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++;
if (cmd[i].c[1] == 'C' && x <= *c0)
dc++;
}
else//删除
{
if (cmd[i].c[1] == 'R' && x == *r0)//删除掉了要查找的数所在的行
return 0;
if (cmd[i].c[1] == 'C' && x == *c0)//删除掉了要查找的数所在的列
return 0;
if (cmd[i].c[1] == 'R' && x < *r0)//删掉了上面的一行,要减少一行序号,不用考虑删掉下面的值,因为位置不会改变
dr--;
if (cmd[i].c[1] == 'C' && x < *c0)//删掉了左边的一列,要减少一列序号,不用考虑删掉右边的值,因为位置不会改变
dc--;
}
}
*r0 += dr;//将位置付给查找的位置并返回打印
*c0 += dc;
}
}
return 1;
}
int main()
{
int r0, c0, q, kase = 0;
while (scanf("%d%d%d", &r, &c, &n) == 3 && r)//输入行,列数和模拟操作次数//输入0 0终止
{
for (int i = 0; i < n; i++)
{
scanf("%s", cmd[i].c);//输入操作模式
if (cmd[i].c[0] == 'E')//交换位置
{
scanf("%d%d%d%d", &cmd[i].r1, &cmd[i].c1, &cmd[i].r2, &cmd[i].c2);//输入要交换的两个坐标
}
else//插入或者删除
{
scanf("%d", &cmd[i].a);//输入要插入或者删除的行或者列的个数
for (int j = 0; j < cmd[i].a; j++)
scanf("%d", &cmd[i].x[j]);//输入要删除的行或者列的序号
}
}
if (kase > 0)
printf("\n");
printf("Spreadsheet #%d\n", ++kase);
scanf("%d", &q);//输入要查找的个数
while (q--)
{
scanf("%d%d", &r0, &c0);//输入要查找的坐标
printf("Cell data in (%d,%d)", r0, c0);
if (!simulate(&r0, &c0))
printf("GONE\n");
else
printf("moved to (%d,%d)\n", r0, c0);
}
}
return 0;
}