题目传送门:https://vjudge.net/problem/UVA-512
题目本身不难,在这儿将两种思路都贴出来,相互学习。
第一种,无脑模拟
#include
#include
#define maxd 100
#define BIG 10000
int r, c, n, d[maxd][maxd], d2[maxd][maxd], ans[maxd][maxd], cols[maxd];/*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];//d2作为d的拷贝,把修改后的表格又重新传回了d
}
else//列操作
{
for(int i = 1; i <= r; i++)
d[i][p] = d2[i][q];
}
}
void del(char type)
{
memcpy(d2, d, sizeof(d));//mencpy()的作用相当于给d做了一个副本,d2就是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);//再最前面也就是0行(列)插入一行(列)
//当前行(列)被覆盖为一个空行(列)
copy(type, ++cnt2, i);//被标记的行标或者列标,就在对应的前面增加一行或者一列
//在标记行(列)的下方还原被标记覆盖的那一行(列),不用担心下一行被覆盖而消失,因为d2从未被改变过
//它里面保存着最原始的表格
}
if(type == 'R') r = cnt2;
else c = cnt2;
}
int main()
{
int r1, c1, r2, c2, q, kase = 0;
char cmd[10];//command 要执行的操作存储在这个字符数组里
memset(d, 0, sizeof(d));
while(scanf("%d%d%d", &r, &c, &n) == 3 && 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--)
{
scanf("%s", cmd);
if(cmd[0] == 'E')//Exchange
{
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));
for(int i = 0; i < a; i++)
{
scanf("%d", &x);
cols[x] = 1;//将待操作列(行)标记为1
}
if(cmd[0] == 'D') del(cmd[1]);
//传入指令首字母为D,必为删除指令,直接调用del函数,在里面判断第二个字母是还是C
else ins(cmd[1]);//既不是EX,又不是Delete,那一定就是插入了,直接调用Ins插入函数
}
}
memset(ans,0,sizeof(ans));
for(int i = 1; i <= r; i++)
for(int j = 1; j <= c; j++) //现在的r和c都是更新后的
ans[d[i][j]/BIG][d[i][j] % BIG] = i * BIG + j; // /BIG得出行标,%BIG得出列标
//d中保存的一直都是自己在原表中的位置
//进行完上述循环之后,ans的label就是待查询cell,ans的值就是待查询cell在当前表中的位置的数值表示
if(kase>0)printf("\n");
printf("Spreadsheet #%d\n", ++kase);
scanf("%d",&q);
while(q--)
{
scanf("%d%d",&r1,&c1);
printf("Cell data in (%d,%d) ",r1,c1);
if(ans[r1][c1]== 0)printf("GONE\n");
else printf("moved to (%d,%d)\n",ans[r1][c1]/BIG,ans[r1][c1]%BIG);
}
}
return 0;
}
第二种,保存操作,查询cell时再进行操作
#include
#include
#define maxd 10000
//不模拟表格更改的操作,现将操作保存起来,到查询的时候再进行操作,只需要专注于待查询cell即可
struct Command {
char c[5];//保存操作
int r1, c1, r2, c2;//记录行数和列数, 这4个成员,只有在Exchange操作中有用
int a, x[20];//待修改r/col个数及r/col的值
} cmd[maxd];//创建指令结构体数组
int r, c, n;
//simulate的参数只有被查询cell的label
int simulate(int* r0, int* c0) {//由于需要更改r0和c0的值,故而传的是地址
for(int i = 0; i < n; i++) {
//要把所有操作全部执行完,才能得出最终结果
if(cmd[i].c[0] == 'E') { //交换操作
//便利找出待查询cell在cmd数组中的位置
if(cmd[i].r1 == *r0 && cmd[i].c1 == *c0) {//同1输2
*r0 = cmd[i].r2; *c0 = cmd[i].c2;
}
else if(cmd[i].r2 == *r0 && cmd[i].c2 == *c0) {//同2输1
*r0 = cmd[i].r1; *c0 = cmd[i].c1;
}
}
else {
int dr = 0, dc = 0;
for(int j = 0; j < cmd[i].a; j++) {//对所有待操作r/col进行相应操作
int x = cmd[i].x[j];//依次取出待操作row/col值
if(cmd[i].c[0] == 'I') {//insert两个分支,ins_row/ins_col
if(cmd[i].c[1] == 'R' && x <= *r0) dr++;
//在cell的r_label及r_label前插入,cell的r_label值都会相应的增加,c_label同理
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;
//待查询cell的r_label值或c_label值被删除,都会立马返回0,simulate程序终止,输出“GONE”
if(cmd[i].c[1] == 'R' && x < *r0) dr--;
//在cell的r_label前删除,cell的r_label值都会相应的减少,c_label同理
if(cmd[i].c[1] == 'C' && x < *c0) dc--;
}
}
*r0 += dr; *c0 += dc;
}
}
return 1;
}
int main() {
int r0, c0, q, kase = 0;//输出序号kase
while(scanf("%d%d%d", &r, &c, &n) == 3 && r) {
for(int i = 0; i < n; i++) {
scanf("%s", cmd[i].c);//传入指令
if(cmd[i].c[0] == 'E') //Exchange需要4位参数,两个cell,在查询时swap即可
scanf("%d%d%d%d", &cmd[i].r1, &cmd[i].c1, &cmd[i].r2, &cmd[i].c2);
else {
scanf("%d", &cmd[i].a);//否则即为删或插操作,待操作row(col)个数
for(int j = 0; j < cmd[i].a; j++)
scanf("%d", &cmd[i].x[j]);//输入label
}
}
if(kase > 0)
printf("\n");
printf("Spreadsheet #%d\n", ++kase);
scanf("%d", &q);//待查询cell个数
while(q--) {
scanf("%d%d", &r0, &c0);//待查询cell的label
printf("Cell data in (%d,%d) ",r0, c0);
if(!simulate(&r0, &c0)) printf("GONE\n");//关键就在于simulate的实现(simulate模拟)
else printf("moved to (%d,%d)\n", r0, c0);
}
}
return 0;
}