uva 196 Spreadsheet
在poj上也有 是poj 1420,在poj上AC了,但是在UVA上RE
题意:很好理解就是给你一个表格,一些元素已经有数字了,一些元素还不知道,但是它等于某些元素相加的和,要你补完整个表格
(行用1到999表示,列用大写字母来表示,用ABC开始一直到ZZZ,这个很容易算出来,26+26*26+26*26*26=18278,字符处理有些麻烦,代码中的funtion函数)
这个东西一开始没想到是什么,后来喵了一下解题报告说是拓扑排序,瞬间就懂了,因为有些元素是未知的,未知的元素是由已知的元素相加得到的,那么就是有一个优先关系,看sample就看得出来
然后数据较大,打了一半不知道要怎么做了,然后又轻轻喵了一下解题报告,说是数据没有这么大,开个1001*1001的数组就可以了,然后就这么做,后面的都没看解题报告了
在拓扑排序建图的时候是同邻接表,然后是用链表来实现的,添加元素的时候用了头插法。建好图记录号入度出度之后,然后就是拓扑排序的常规实现了
注释都在代码中,直接看代码,还要再改改代码才能在UVA中AC啊………………
在POJ上AC的
#include <cstdio> #include <cstring> #include <cstdlib> #include <queue> using namespace std; #define N 1010 //行1-999 int n,m; struct node { int x,y; struct node *next; }; struct SHEET { int in,out; int v; struct node *first; //邻接表 }sheet[N][N*100]; //据说开到这么大就可以了,18278是吓人的 struct QUEUE { int x,y; }; queue <struct QUEUE> q; void init() { for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) { sheet[i][j].in=sheet[i][j].out=sheet[i][j].v=0; sheet[i][j].first=NULL; } return ; } void funtion(char *s , int i , int j) { int len,llen,k,tt,r,c; struct node *p; char t[100]; len=strlen(s); k=1; while(k<len) { tt=0; while(s[k]>='A' && s[k]<='Z') t[tt++]=s[k++]; t[tt]='\0'; llen=strlen(t); if(llen==1) c=t[0]-'A'+1; else if(llen==2) c=26 + (t[1]-'A'+1) + (t[0]-'A'+1-1)*26; else //英文字母长度是3 c=26+26*26+ (t[2]-'A'+1) + (t[1]-'A'+1-1)*26 + (t[0]-'A'+1-1)*26*26; sscanf(s+k,"%d",&r); while(s[k]>='1' && s[k]<='9') k++; k++; //printf("行%d 列%d\n",r,c); sheet[i][j].in++; //没分解出一个元素就要令入度+1 sheet[r][c].out++; //出度+1 p=(struct node*)malloc(sizeof(struct node)); p->x=i; p->y=j; p->next=sheet[r][c].first; //头插法 sheet[r][c].first=p; //头插法 } } void input() { int len; char s[1100]; scanf("%d%d",&m,&n); //先输入列再是行别搞错了 init(); //初始化 for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { scanf("%s",s); if(s[0]=='=') funtion(s,i,j); //字符串处理 else sscanf(s,"%d",&sheet[i][j].v); } } /* for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) printf("%d\\%d\\%d ",sheet[i][j].v,sheet[i][j].out,sheet[i][j].in); printf("\n"); } printf("打印邻接表\n"); for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) if(sheet[i][j].out) { struct node *tmp; tmp=sheet[i][j].first; printf("打印 %d %d 邻接表\n",i,j); while(tmp) { printf("%d %d\n",tmp->x,tmp->y); tmp=tmp->next; } } */ return ; } void topsort() { struct QUEUE t1,t2; struct node t,*p; while(!q.empty()) q.pop(); for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) //先扫描所有元素,把所有入度为0的元素放入队列 //其实就是已经知道了数值不需要计算的元素 if(!sheet[i][j].in) { t1.x=i; t1.y=j; q.push(t1); //入度 } while(!q.empty()) { t1=q.front(); //读取队头元素信息 q.pop(); //队友元素出队 int x=t1.x , y=t1.y; if(sheet[x][y].out) //在表格中(x , y)这个元素有出度,那么就删除它的所有的弧,弧头的入度也要记得-1 { p=sheet[x][y].first; int xx,yy; while(p) { xx=p->x; yy=p->y; p=p->next; sheet[xx][yy].in--; //对应弧头的入度-1 sheet[xx][yy].v += sheet[x][y].v; //计算(xx,yy)的值 if(!sheet[xx][yy].in) //删除弧之后如果弧头的入度为0则入队 { t2.x=xx; t2.y=yy; q.push(t2); } } sheet[x][y].first=NULL; //这个弧尾的弧已经全部删除了 } } } int main() { int T; scanf("%d",&T); while(T--) { input(); topsort(); //开始拓扑排序 for(int i=1; i<=n; i++) { int j=1; printf("%d",sheet[i][j].v); for(j=2; j<=m; j++) printf(" %d",sheet[i][j].v); printf("\n"); } printf("\n"); } return 0; }
在UVA上AC的
(下面是一个很有爱的故事)
今天早上上UVA不知道干嘛超慢,页面半天打不开,然后我在想是不是因为十八大的原因…………(以为又封锁了国外网站什么的)
然后这题在poj过了之后就开始交UVA,一直RE,网上都说数组开到1010*1010就可以了,后来我变为1010*10100之后就不RE了变为WA,然后就检查代码,发现了很多小BUG,例如m写成n,0写成1之类的,所以,在这种情况下POJ都能通过那真的是无语了,然后就改了小BUG,提交一直WA,然后期间又把数组改为1010*1010,又RE,所以就确定了数组使1010*10100,就一直WA,最后去看UVA的讨论版,某个人说过不了,给了几个数据我拿几个数据去测试,是对的,这下子有去面壁。后来发现一个问题,在每个表格输出之后是没有空行的,咦好像是要空行的,然后上网又查代码,发现居然有些人有空行有些人没有!!!!
然后我就消掉空行,提交居然AC了!!!!!就是这个空行啊!!!!!
然后又加了空行再交了几次,确定了,每个表格后面是不用空行的(那些有空行的人是怎么AC的………………)
然后又丢到poj上去,我去!!!!poj有没有空行都能通过的,这是一个多么有爱的故事
这个故事还没有完,要知道我提交是在UVA失常页面老是打不开的情况下提交的,那个心情的
而就在我第一次AC之后………………UVA恢复正常了………………
我的一个晚上又废掉了…………本来今晚要学英语的…………都九点半了…………
献上代码,和poj那个代码是一样的,修改了一些小BUG,不要看POJ那个代码了,直接看这个!
#include <cstdio> #include <cstring> #include <cstdlib> #include <queue> using namespace std; #define N 1010 //行1-999 int n,m; struct node { int x,y; struct node *next; }; struct SHEET { int in,out; int v; struct node *first; //邻接表 }sheet[N][N]; //据说开到这么大就可以了,18278是吓人的 struct QUEUE { int x,y; }; queue <struct QUEUE> q; void init() { for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) { sheet[i][j].in=sheet[i][j].out=sheet[i][j].v=0; sheet[i][j].first=NULL; } return ; } void funtion(char *s , int i , int j) { int len,llen,k,tt,r,c; struct node *p; char t[100]; len=strlen(s); k=1; while(k<len) { tt=0; while(s[k]>='A' && s[k]<='Z') { t[tt]=s[k]; tt++; k++; } t[tt]='\0'; llen=strlen(t); if(llen==1) c=t[0]-'A'+1; else if(llen==2) c=(t[1]-'A'+1) + (t[0]-'A'+1)*26; else //英文字母长度是3 c=(t[2]-'A'+1) + (t[1]-'A'+1)*26 + (t[0]-'A'+1)*26*26; sscanf(s+k,"%d",&r); while(s[k]>='0' && s[k]<='9') k++; //printf("%s\n",t); //printf("行%d 列%d\n",r,c); k++; sheet[i][j].in++; //没分解出一个元素就要令入度+1 sheet[r][c].out++; //出度+1 p=(struct node*)malloc(sizeof(struct node)); p->x=i; p->y=j; p->next=sheet[r][c].first; //头插法 sheet[r][c].first=p; //头插法 } return ; } void input() { int len; char s[110000]; scanf("%d%d",&m,&n); //先输入列再是行别搞错了 init(); //初始化 for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { scanf("%s",s); if(s[0]=='=') funtion(s,i,j); //字符串处理 else sscanf(s,"%d",&sheet[i][j].v); } } /* for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) printf("%d\\%d\\%d ",sheet[i][j].v,sheet[i][j].out,sheet[i][j].in); printf("\n"); } printf("打印邻接表\n"); for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) if(sheet[i][j].out) { struct node *tmp; tmp=sheet[i][j].first; printf("打印 %d %d 邻接表\n",i,j); while(tmp) { printf("%d %d\n",tmp->x,tmp->y); tmp=tmp->next; } } */ return ; } void topsort() { int x,y,xx,yy; struct QUEUE t1,t2; struct node t,*p; while(!q.empty()) q.pop(); for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) //先扫描所有元素,把所有入度为0的元素放入队列 //其实就是已经知道了数值不需要计算的元素 if(!sheet[i][j].in) { t1.x=i; t1.y=j; q.push(t1); //入度 } while(!q.empty()) { t1=q.front(); //读取队头元素信息 q.pop(); //队友元素出队 x=t1.x ; y=t1.y; if(sheet[x][y].out) //在表格中(x , y)这个元素有出度,那么就删除它的所有的弧,弧头的入度也要记得-1 { p=sheet[x][y].first; while(p) { xx=p->x; yy=p->y; p=p->next; sheet[xx][yy].in--; //对应弧头的入度-1 sheet[xx][yy].v += sheet[x][y].v; //计算(xx,yy)的值 if(!sheet[xx][yy].in) //删除弧之后如果弧头的入度为0则入队 { t2.x=xx; t2.y=yy; q.push(t2); } } sheet[x][y].first=NULL; sheet[x][y].out=0; //这个弧尾的弧已经全部删除了 } } } int main() { int T; scanf("%d",&T); while(T--) { input(); topsort(); //开始拓扑排序 for(int i=1; i<=n; i++) { int j=1; printf("%d",sheet[i][j].v); for(j=2; j<=m; j++) printf(" %d",sheet[i][j].v); printf("\n"); } //printf("\n"); //我靠…………就是这个东西,WA了3小时………………本来1A的……为什么UVA和POJ这么坑的………… } return 0; }