求助 已经AC 但不是很理解这个做法
查看原帖
求助 已经AC 但不是很理解这个做法
232205
little_kongbai楼主2022/7/10 21:28

题目要求如果输出 NO 的话要在第二行输出最小的不能控制间谍的编号

在我的做法中,我对于缩点后的每个点计算入度,如果这个缩点后的点 入度为 0 且缩点后的点内没有间谍可以贿赂,则将这个缩点后的点内最小的间谍编号与答案的最小取min

我的问题在于:由于我是在入度为0处找编号最小,但如果入度为0这个点没法被贿赂,那这个入度为0连接的后面的点也无法贿赂,怎么保证后面的点中编号都比入度为0的这个点大呢?

Code:

	#include<bits/stdc++.h>
	#define inf 0x7f7f7f7f
	using namespace std;
	int n,p,tot,a,b,c,pr[3005],minid[3005],head[3005],ru[3005],cost[3005],dfn[3005],low[3005],color[3005],T,ans,cnt,loss[3005],ANS;
	stack<int>s;bool inz[3005];
	struct node{
		int to,next;
	}e[10000005];
	void add(int a,int b){
		e[++tot].to=b;
		e[tot].next=head[a];
		head[a]=tot;
	}
	void tarjan(int v){
		dfn[v]=low[v]=++T;inz[v]=1;
		s.push(v);
		for(int i=head[v];i;i=e[i].next){
			int to=e[i].to;
			if(!dfn[to])tarjan(to),low[v]=min(low[v],low[to]);
			else if(inz[to]) low[v]=min(low[v],dfn[to]);
		}
		if(dfn[v]==low[v]){
			int t;++ans;
			do{
				t=s.top(),s.pop();inz[t]=0;
				cost[ans]=min(cost[ans],pr[t]);
				minid[ans]=min(minid[ans],t);
				color[t]=ans;
			}while(t!=v);
		}
	}
	int main(){
		scanf("%d%d",&n,&p);
		memset(pr,0x7f,sizeof pr);
		memset(cost,0x7f,sizeof cost);
		memset(minid,0x7f,sizeof minid);
		for(int i=1;i<=p;i++){
			scanf("%d%d",&a,&b);
			pr[a]=b;
		}
		scanf("%d",&c);
		while(c--){
			scanf("%d%d",&a,&b);
			add(a,b);
		}
		for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i);
		for(int i=1;i<=n;i++) for(int j=head[i];j;j=e[j].next){
			if(color[i]!=color[e[j].to])++ru[color[e[j].to]];
		}
		bool f=0;int id=inf,all=0;
		for(int i=1;i<=ans;i++){
			if(ru[i])continue;
			if(cost[i]==inf){
				f=1; id=min(id,minid[i]);
			}
			if(!f) all+=cost[i];
		}
		if(f) printf("NO\n%d",id);
		else printf("YES\n%d",all);
		return 0;
	}
2022/7/10 21:28
加载中...