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;
}

 

 

 

posted @ 2012-11-14 18:10  Titanium  阅读(529)  评论(0编辑  收藏  举报