NOIP 2013 普及组 复赛 level 车站分级

NOIP 2013 普及组 复赛 level 车站分级

该题有个难点,输入数据有重边,处理不好,会有RE问题,这个问题是编到最后3个测试点时的问题。2018-11-2 9:43

//以下代码为 bfs广搜+邻接表 的拓扑排序,写的很棒,发现是 2018-04-27 21:06 编写的

#include <stdio.h>
#include <string.h>
#define maxn 1100
int map[maxn][maxn],a[maxn],vis[maxn],rd[maxn],q[maxn],head[maxn],cnt=0;//q[i]队列
struct node{
    int to;
    int next;
}e[maxn*maxn/2];
void add(int u,int v){
    cnt++,e[cnt].to=v,e[cnt].next=head[u],head[u]=cnt;
}
int main(){
    int n,m,i,j,si,k,ans=0,h,t,x,b,v;
    memset(map,0,sizeof(map)),memset(rd,0,sizeof(rd)),memset(head,0,sizeof(head));
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++){//读取数据
        memset(a,0,sizeof(a)),memset(vis,0,sizeof(vis));
        scanf("%d",&si);
        for(j=1;j<=si;j++)
            scanf("%d",&a[j]),vis[a[j]]=1;//此处写成 vis[j]=1 昏招  
        for(k=a[1]+1;k<=a[si]-1;k++)
            if(vis[k]==0)
                for(j=1;j<=si;j++)
                    if(map[k][a[j]]==0)
                        map[k][a[j]]=1,add(k,a[j]),rd[a[j]]++;
    }
    memset(vis,0,sizeof(vis));//此句需写在 循环while(1)之外
    while(1){
        h=t=1;
        for(i=1;i<=n;i++)
            if(vis[i]==0&&rd[i]==0)
                vis[i]=1,q[t]=i,t++;        
        if(h==t)break;//无入度为0的点,跳出循环
        while(h<t){
            x=q[h];
            b=head[x];
            while(b){
                v=e[b].to;
                rd[v]--;
                b=e[b].next;
            }
            h++;
        }
        ans++;
    }
    printf("%d",ans);
    return 0;
}

//以下代码为 bfs广搜+邻接矩阵 的拓扑排序,写的很棒,发现是 2018-04-27 19:03 编写的

#include <stdio.h>
#include <string.h>
#define maxn 1100
int map[maxn][maxn],a[maxn],vis[maxn],rd[maxn],q[maxn];//q[i]队列 
int main(){
    int n,m,i,j,si,k,cnt=0,h,t,x;
    memset(map,0,sizeof(map)),memset(rd,0,sizeof(rd));
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++){//读取数据 
        memset(a,0,sizeof(a)),memset(vis,0,sizeof(vis));
        scanf("%d",&si);
        for(j=1;j<=si;j++)
            scanf("%d",&a[j]),vis[a[j]]=1;//此处写成 vis[j]=1 昏招  
        for(k=a[1]+1;k<=a[si]-1;k++)
            if(vis[k]==0)
                for(j=1;j<=si;j++)
                    if(map[k][a[j]]==0) 
                        map[k][a[j]]=1,rd[a[j]]++;
    }
    memset(vis,0,sizeof(vis));//此句需写在 循环while(1)之外 
    while(1){
        h=t=1;
        for(i=1;i<=n;i++)
            if(vis[i]==0&&rd[i]==0)
                vis[i]=1,q[t]=i,t++;        
        if(h==t)break;//无入度为0的点,跳出循环
        while(h<t){
            x=q[h];
            for(i=1;i<=n;i++)//去除  入度为0 的点 对应的连线
                if(map[x][i])
                    map[x][i]=0,rd[i]--;
            h++;
        }
        cnt++;
    }
    printf("%d",cnt);
    return 0;
}

//以下代码为 dfs深搜+邻接表 的 树的最大深度,写的很棒,发现是 2018-04-28 17:34 编写的

#include <stdio.h>
#include <string.h>
#define maxn 1100
int map[maxn][maxn],a[maxn],vis[maxn],rd[maxn],head[maxn],cnt=0,d[maxn];//d[i] i点深度 
struct node{
    int to;
    int next;
}e[maxn*maxn/2];
void add(int u,int v){
    cnt++,e[cnt].to=v,e[cnt].next=head[u],head[u]=cnt;
}
int max(int a,int b){
    return a>b?a:b;
}
int dfs(int u){
    int b,v;
    if(d[u]){//记忆化搜索 
        return d[u];
    }
    d[u]=1,b=head[u];
    while(b){
        v=e[b].to;
        d[u]=max(d[u],dfs(v)+1);
        b=e[b].next;
    }
    return d[u];
}
int main(){
    int n,m,i,j,si,k,ans=0,h,t,x,b,v;
    memset(map,0,sizeof(map)),memset(rd,0,sizeof(rd)),memset(head,0,sizeof(head)),memset(d,0,sizeof(d));
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++){//读取数据
        memset(a,0,sizeof(a)),memset(vis,0,sizeof(vis));
        scanf("%d",&si);
        for(j=1;j<=si;j++)
            scanf("%d",&a[j]),vis[a[j]]=1;//此处写成 vis[j]=1 昏招  
        for(k=a[1]+1;k<=a[si]-1;k++)
            if(vis[k]==0)
                for(j=1;j<=si;j++)
                    if(map[a[j]][k]==0)
                        map[a[j]][k]=1,add(a[j],k),rd[k]++;
    }
    for(i=1;i<=n;i++)
        if(rd[i]==0)
            ans=max(ans,dfs(i));
    printf("%d",ans);
    return 0;
}

//P1983 车站分级
//拓扑排序,此文代码写得不错http://hzwer.com/767.html
//思路角度,此文不错http://blog.csdn.net/yuyanggo/article/details/48914523摘抄如下:
//拓扑排序。
//火车停靠站的级别总是高于未停靠站的,类似于拓扑排序里的先后顺序。
//假设一列火车的起点站为 s ,终点站为 e ,则途中的所有停靠站向未停靠站连一条边,表示停靠站的级别高于未停靠站,这样处理之后,就得到一个AOV图。
//对改图反复执行操作:
//1.将所有入度读为零的点入栈。
//2.将栈中所有点相连的边去掉,相连的点入度 -1。
// (对相连点进行判断,若入度为零,则保存起来。因为下一批入度为零的点必然是与本批入读为零的点项相连的)
//执行次数即为答案。
//根据样例,跟踪了代码,弄明白了拓扑排序的思路。同时也根据样例构建了该题,样例对应的AOV图.
//编码很快,调试很慢,调了30分钟,样例1,样例2通过后,提交AC.2017-6-21 23:10
#include <stdio.h>
#include <string.h>
int book[1000+10],a[1000+10],e[1000+10][1000+10],rd[1000+10],stack[1000+10];
int main(){
    int n,m,i,j,k,q,top,ans=0;    
    memset(e,0,sizeof(e));
    memset(rd,0,sizeof(rd));
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++){//计算有向图,入度
        scanf("%d",&q);
        memset(book,0,sizeof(book));//3 放错位置,之前放在上面的for循环之外
        for(j=1;j<=q;j++){
            scanf("%d",&a[j]);
            book[a[j]]=1;
        }
        for(j=a[1];j<=a[q];j++)
            if(book[j]==0){
                for(k=1;k<=q;k++)
                    if(e[j][a[k]]==0){//2 漏了该句,该句目的,避免重复计数
                        e[j][a[k]]=1;//联通,有向图
                        rd[a[k]]++;
                    }
            }     
    }
    memset(book,0,sizeof(book));//1 该句写错位置,写到while循环内部
    while(1){
        top=-1;        
        for(i=1;i<=n;i++)
            if(book[i]==0&&rd[i]==0){
                top++;
                stack[top]=i;
                book[i]=1;
            }
        if(top==-1)
            break;//跳出循环
        for(i=0;i<=top;i++)
            for(j=1;j<=n;j++)
                if(e[stack[i]][j]==1){
                    e[stack[i]][j]=0;
                    rd[j]--;
                }
        ans++;
    }
    printf("%d\n",ans);
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值