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