求大佬帮忙!!!92分第8个点卡了
查看原帖
求大佬帮忙!!!92分第8个点卡了
332127
YiNian_Xuan楼主2020/7/29 17:28

代码如下:

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

int n,p,money[3005],m,dfn[3005],low[3005],num,cnt,mark[3005],minm[3005],inpoint[3005],ans;
bool buy[3005],vis[3005],flag[3005][3005];
const int MAXM=100000;
vector <int> G[3005];
stack <int> s;

void input() {
	cin>>n>>p;
	int idx;
	for(int i=0;i<p;i++) {
		cin>>idx;
		cin>>money[idx];
		buy[idx]=1;
	}
	cin>>m;
	int a,b;
	for(int i=0;i<m;i++) {
		cin>>a>>b;
		G[a].push_back(b);
	}
} 

void Tarjan(int i) {
	dfn[i]=low[i]=++num;
	s.push(i);
	for(int j=0;j<G[i].size();j++) {
		if(!dfn[G[i][j]]) {
			Tarjan(G[i][j]);
			low[i]=min(low[i],low[G[i][j]]);
		}
		else if(!mark[G[i][j]])
			low[i]=min(low[i],dfn[G[i][j]]);
	}
	if(low[i]==dfn[i]) {
		cnt++;
		while(s.top()!=i) {
			mark[s.top()]=cnt;
			if(money[s.top()]<minm[cnt]) minm[cnt]=money[s.top()];
			s.pop();
		}
		mark[s.top()]=cnt;
		if(money[s.top()]<minm[cnt]) minm[cnt]=money[s.top()];
		s.pop();
	}
}

int main()
{
	for(int i=0;i<3005;i++) {
		minm[i]=money[i]=MAXM;
	}
	input();
	for(int i=1;i<=n;i++)
		if(!dfn[i] && buy[i]) Tarjan(i);
	for(int i=1;i<=n;i++)
		if(!dfn[i]) {
			cout<<"NO\n"<<i<<endl;
			return 0;
		}
	for(int i=1;i<=n;i++) {
		if(!buy[i]) continue;
		for(int j=0;j<G[i].size();j++) {
			if(mark[i]!=mark[G[i][j]] && !flag[mark[i]][mark[G[i][j]]]) {
				inpoint[mark[G[i][j]]]++;
				flag[mark[i]][mark[G[i][j]]]=1;
			}
		}
	}
	for(int i=1;i<=cnt;i++) {
		if(inpoint[i]==0 && minm[i]!=MAXM) ans+=minm[i];
	}
	cout<<"YES\n"<<ans<<endl;
	return 0;
}

我的思路:

其实我就想的是先用Tarjan算法求SCC,同时记录每个点的SCC号码(就那个mark数组),以及每个SCC的最小花费(minm数组)。

然后main函数里面,输入+Tarjan后,先判断有没有没遍历过的点,有就说明不能控制所有间谍。随后再缩点(如果我这个算缩点的话),就把每个SCC当成一个整体,检索边,相应的SCC的入度增加1。最后再遍历每一个“SCC点”,入度为1的将其minm加到ans里。

求助大佬这样的方法哪里有问题,谢谢!!

2020/7/29 17:28
加载中...