文章目录
- 题目描述
- 解析
- 代码
题目描述
解析
乍一看:是个水题啊!
显然如果途径存在强连通的点,路径就会变为正无穷
所以缩点加拓扑dp以及一些特判应该就可以解决了!
一交:40分。。。
然后就开始拆东墙补西墙的debug。。。
de到80之后实在无计可施,看了测试数据
最终在交了10余次后切掉了本题(泪目)
总结一下遇见的问题吧:
1.是所以超过36500的点视为相等,而不是有超过36500的点就全部认为相等!(gg:省选的亏还是没吃够啊。。。)
2.判断强连通特判的位置应该在topu的while大循环的里面而不是判断出边的地方(如果这里不像人话可以看下面的代码有注释说明),否则入度为0的强连通会统计不上
3.有自环!!!!路径也相当于正无穷!(就是这个地方卡80分一直没想到,以后要培养题里没说没有就要考虑自环、重复路径的思维)
4.在2的判断的位置,不是所有有自环的或强连通都是可以的,至少。。它得能走到n+1点啊。。。
总的来说,本题是一道考验严谨思维的题,数据出的很好,提升了本题的质量
我也要提升自己的质量!
代码
#include<bits/stdc++.h>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=2e6+100;
const int M=2e6+100;
const int X=36500;
int n,m;
int cnt=-1,fi[N];
struct node{int to,nxt;
}p[M];
void addline(int x,int y){p[++cnt]=(node){y,fi[x]};fi[x]=cnt;
}
int a,b;
int zhan[N],dfs[N],low[N],col[N];
int ed,tot,tim;
int size[N];
int self[N];
void tarjan(int x){zhan[++ed]=x;dfs[x]=low[x]=++tim;for(int i=fi[x];~i;i=p[i].nxt){int u=p[i].to;if(dfs[u]==0){tarjan(u);low[x]=min(low[x],low[u]);}else if(col[u]==0) low[x]=min(low[x],low[u]);}if(low[x]==dfs[x]){col[x]=++tot;size[tot]=1;if(self[x]) self[tot]=1;while(zhan[ed]!=x){if(self[zhan[ed]]) self[tot]=1;col[zhan[ed--]]=tot;size[tot]++;}ed--;}
}
int flag,dp[N],ru[N];
void topu(){queue<int>q;for(int i=n+1;i<=tot;i++) if(ru[i]==0) q.push(i);while(!q.empty()){int now=q.front();q.pop();
// printf("now=%d\n",now);if(self[now]&&dp[now]||dp[now]>X||(dp[now]&&size[now]!=1)){dp[now]=36501;}//刚才第二条说的就是上面的这个特判不能写在下面的A处for(int i=fi[now];~i;i=p[i].nxt){int u=p[i].to;//A处就是这里啦
// printf("now=%d to=%d\n",now,u);dp[u]+=dp[now];if(--ru[u]==0){q.push(u);}}}
}
int ans,num,jd[N];
int main(){scanf("%d%d",&n,&m);n++;tot=n;mem(fi,-1);for(int i=1;i<=m;i++){scanf("%d%d",&a,&b);if(a==b) self[a]=1;else addline(b,a);//反向建图 }for(int i=1;i<=n;i++){if(!dfs[i]) tarjan(i);}for(int i=1;i<=n;i++){int xx=col[i];for(int j=fi[i];~j;j=p[j].nxt){int yy=col[p[j].to];if(xx!=yy){addline(xx,yy);ru[yy]++;}}}
// for(int i=1;i<=n+1;i++) printf("i=%d col=%d size=%d\n",i,col[i],size[col[i]]);dp[col[n]]=1;topu();
// for(int i=1;i<=n;i++) printf("i=%d dp=%d\n",i,dp[col[i]]); for(int i=n+1;i<=tot;i++){if(dp[i]>36500){flag=1,ans=36501;break;}else ans=max(ans,dp[i]);}for(int i=n+1;i<=tot;i++){if(dp[i]>=ans){num+=size[i];jd[i]=1;}}if(ans<=36500) printf("%d\n",ans);else printf("zawsze\n");printf("%d\n",num);for(int i=1;i<=n;i++){if(jd[col[i]]) printf("%d ",i);}return 0;
}
/*
3 2
3 4
4 3
*/