关于这题为啥不能用拓扑排序和请求添加 hack 数据
查看原帖
关于这题为啥不能用拓扑排序和请求添加 hack 数据
772999
jr_zch楼主2023/12/26 17:11

其实很显然,自己画个图就可以很快发现问题

如上图所示,如果用拓扑序,点 11 会先让 点 22、33 的价值分别加 11,然后点 22 会让点 33 的贡献再加 22,而这个 22 实际上含有了点 11。

这样一来点 11 的贡献就在点 33 被算了两次。

下面是我用拓扑序写的 WA 64ptsWA~64pts 的代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn=1e5+7;
int n,m,u,v,cnt,top,tot,ans;
int dfn[maxn],low[maxn],stk[maxn],scc[maxn],d[maxn],siz[maxn],du[maxn],f[maxn];
vector<int> e[maxn],c[maxn];
queue<int> q;

void dfs(int u){
	dfn[u]=low[u]=++cnt;
	stk[++top]=u;
	for(int i=0;i<e[u].size();i++){
		int v=e[u][i];
		if(!dfn[v]){
			dfs(v);
			low[u]=min(low[u],low[v]); 
		}else if(!scc[v]) low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u]){
		tot++;
		while(1){
			int v=stk[top--];
			scc[v]=tot,siz[tot]++;
			if(u==v) break;
		}
	}
	return ;
}

void topu(){
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=0;i<c[u].size();i++){
			int v=c[u][i];
			du[v]+=du[u]+1,d[v]--;
			if(!d[v]) q.push(v);
		}
	}
	return ;
}
 
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++) scanf("%d%d",&u,&v),e[u].push_back(v);
	for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
	for(int u=1;u<=n;u++){
		for(int j=0;j<e[u].size();j++){
			if(scc[u]!=scc[e[u][j]]){
				c[scc[u]].push_back(scc[e[u][j]]);
				d[scc[e[u][j]]]++;
			}
		}
	}
	for(int i=1;i<=tot;i++) if(!d[i]) q.push(i);
	topu();
	for(int i=1;i<=tot;i++){
		if(du[i]+1==tot){
			ans=siz[i];
			break;
		}
	}
	printf("%d",ans);
	return 0;
}

但是我如果在统计答案时这样子改:

for(int i=1;i<=tot;i++){
//	if(du[i]+1==tot){ ——这是原来的
 	if(du[i]+1>=tot){
		ans=siz[i];
		break;
	}
}

就可以得到 ACAC,说明数据太水了。

下面给出 33 组 hack 数据:

input1:
4 3
1 2
2 3
1 3
  
output1:
0
  
input2:
18 22
4 5
5 3
1 2
2 3
1 3
6 7 
7 6
6 3
3 8
8 3
8 9
9 10
10 11
11 12
12 13
13 9
14 15
15 16
16 17
17 18
18 14
4 18
  
output2:
0
  
input3:
9 11
4 5
5 3
1 2
2 3
1 3
6 7 
7 6
6 3
3 8
8 3
8 9
  
output3:
1
2023/12/26 17:11
加载中...