UVA 196 POJ 1420 (拓扑排序--删边法)

拓扑排序;
刚开始想的直接模拟,但没考虑到要是表达式里给的还没给出的边的话,就没法算呀。
看了吴永辉老师的题解,才明白是要进行拓扑排序,想想也很有道理,在我看来删边法最重要的三个部分:入度,邻接表,队列。
正好,这道题满足这三个条件,入度为零的点即为已知的点,压入队列中,对每个表达式项( i , j ),取出其中的每一项,计算其对应的行号 X 列号 Y ,(i,j)送入(x,y)的邻接表中,并累计(i,j)的入度。
从队列中取出入度为零的点,进行删边操作。同时给对应的边赋值,将过程中入度变为0的点压入队列中,往复直到队列为空。
这样的拓扑排序就构造成功。
code 如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<list>
#include<queue>
#define mm(a,b) memset(a,b,sizeof(a))
#define ACCELERATE (ios::sync_with_stdio(false),cin.tie(0))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
using namespace std;
int mmp[100][100];

struct point{
    int x;
    int y;
    point(int a,int b):x(a),y(b){}
};

list<point> g[100][100];

int ind[100][100];

int main()
{
    int n;
    scanf("%d",&n);
    while(n--){
        char s[100];
        int a,b;
        scanf("%d%d",&a,&b);
        memset(mmp,0,sizeof(mmp));
        memset(ind,0,sizeof(ind));
        for(int i=1;i<=b;i++){
            for(int j=1;j<=a;j++){
                scanf("%s",s);
                if(s[0]=='='){
                    int ans=0;
                    char alpha[4];
                    char digit[4];
                    int j1=0,j2=0;
                    for(int k=1;s[k];k++){
                        if(isalpha(s[k])) alpha[j1++]=s[k];
                        else if(isdigit(s[k])) digit[j2++]=s[k];
                        else{
                            int col=0,row=0;
                            while((--j1)>=0){
                                int flag=26;
                                col=col*26+alpha[j1]-64;
                            }
                            while((--j2)>=0){
                                int flag=10;
                                row=row*10+digit[j2]-48;
                            }
                            ind[i][j]++;
                            point t(i,j);
                            g[row][col].push_back(t);
                            j1=j2=0;
                        }
                    }
                    int col=0,row=0;
                    while((--j1)>=0){
                        int flag=26;
                        col=col*26+alpha[j1]-64;
                    }
                    while((--j2)>=0){
                        int flag=10;
                        row=row*10+digit[j2]-48;
                    }
                    ind[i][j]++;
                    point t(i,j);
                    g[row][col].push_back(t);
                }else mmp[i][j]=atoi(s);
            }
        }
        queue<point> q;
        for(int i=1;i<=b;i++){
            for(int j=1;j<=a;j++){
                if(ind[i][j]==0){
                    point t(i,j);
                    q.push(t);
                }
            }
        }
        while(!q.empty()){
            point t=q.front();
            q.pop();
            for(list<point>::const_iterator it=g[t.x][t.y].begin();it!=g[t.x][t.y].end();it++){
                mmp[it->x][it->y]+=mmp[t.x][t.y];
                ind[it->x][it->y]--;
                if(ind[it->x][it->y]==0){
                    q.push(point(it->x,it->y));
                }

            }
        }
        for(int i=1;i<=b;i++){
            for(int j=1;j<=a;j++){
                if(j!=1) printf(" ");
                printf("%d",mmp[i][j]);
            }
            puts("");
        }
        for(int i=1;i<=b;i++){
            for(int j=1;j<=a;j++){
                if(!g[i][j].empty())  g[i][j].clear();
            }
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值