scoi2011糖果求助,wa1+tle2,代码有注释
  • 板块灌水区
  • 楼主Flying_hp
  • 当前回复0
  • 已保存回复0
  • 发布时间2024/10/20 17:26
  • 上次更新2024/10/20 19:31:29
查看原帖
scoi2011糖果求助,wa1+tle2,代码有注释
1123665
Flying_hp楼主2024/10/20 17:26
基本思路:
只考虑1,3,5的情况,绕后Tarjan缩点。
再考虑2,4的情况,并重构图。
最后拓扑排序,并检查是否为DAG。
若为,则输出答案,否则输出-1;
#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct node{ 
	ll root,add;//点,权值 
};
ll n,k;
ll dfn[100010],tot=0;//深度,总深度 
bool instack[100010];//在栈里 
ll low[100010];//每个点的临时scc头 
ll co[100010],col=0;//记录该第几个颜色,以及每个店的颜色 
stack<ll>stk;//Tarjan的栈 
vector<node>v[100010];//原图储存 
vector<node>p[100010];//重构图储存 
ll x[100010],y[100010],z[100010];//储存条件 
ll top_scc[100010];//每个scc的头 
ll of_scc[100010];//每个点对应的scc 
ll cnt;//有几个点处理过了 
ll na[100010];//映射:scc中的点->scc的头 
ll rd[100010];//每个点的入度 
ll dp[100010];//储存每个点的最小权值 
ll cnt_scc[100010];//scc中节点数量 
queue<node>q;//拓扑专用队列 
ll used=0;//通过已访问节点数量,判断是否为DAG 
void Tarjan(ll u) {//Tarjan模版 
	dfn[u]=++tot;
	low[u]=dfn[u];
	stk.push(u);
	instack[u]=true;
	for(ll e=0;e<v[u].size();e++){
		ll vr=v[u][e].root;
		if(!dfn[vr]){
			Tarjan(vr);
			low[u]=min(low[u],low[vr]);
		}else if(instack[vr]){
			low[u]=min(low[u],dfn[vr]);
		}
	}
	if(low[u]==dfn[u]){
		++col;
		co[u]=col;
		top_scc[col]=u;
		cnt++;
		na[u]=u;
		cnt_scc[col]=1;
		of_scc[u]=col;
		while(stk.top()!=u)na[stk.top()]=u,co[stk.top()]=col,instack[stk.top()]=false,stk.pop(),cnt++,cnt_scc[col]++;
		instack[u]=false;
		stk.pop();
	}
}
void topu(){//拓扑模版 
	for(ll i=1;i<=n;i++){
		if(rd[i]==0&&na[i]==i)
		dp[i]=1,q.push({i,1});
		else
		dp[i]=0;
	}
	while(q.size()){
		ll f=q.front().root;
		q.pop();
		used++;
		for(ll i=0;i<p[f].size();i++){
			ll rt=p[f][i].root,ad=p[f][i].add;
			rd[rt]--;
			dp[rt]=max(dp[rt],dp[f]+ad);
			if(rd[rt]==0){
				q.push({rt,dp[rt]});
			}
		}
	}
	if(used>=col){
		ll ans=0;
		for(ll i=1;i<=n;i++){
			if(na[i]==i){
				ans+=cnt_scc[of_scc[i]]*dp[i];//每个scc的节点数*头的权值 
			}
		}
		cout<<ans;
	}
	else{
		cout<<-1;
	}
}
signed main(){
	cin>>n>>k;
	for(ll i=1;i<=k;i++){//只考虑1,3,5的情况,建边原则为:
						 //x->y,权值为w,w=0或1,代表y的值至少为x的值+w
		cin>>x[i]>>y[i]>>z[i];
		if(x[i]==1){//等于时各自连边 
			v[y[i]].push_back({z[i],0});
			v[z[i]].push_back({y[i],0});
		}
		if(x[i]==3){
			v[z[i]].push_back({y[i],0});
		}
		if(x[i]==5){
			v[y[i]].push_back({z[i],0});
		}
	}
	while(cnt<n){//图可以为非联通图,所以需要把每一个图各自Tarjan 
		ll id;
		for(ll i=1;i<=n;i++){
			if(co[i]==0){
				id=i;
				break;
			}
		}
		Tarjan(id);
	}
	for(ll i=1;i<=k;i++){//重构图 
		if(x[i]==1)continue;
		if(x[i]==3){
			if(z[i]==na[z[i]]&&na[y[i]]!=z[i])
			p[z[i]].push_back({na[y[i]],0});
		}
		if(x[i]==5){
			if(y[i]==na[y[i]]&&na[z[i]]!=y[i])
			p[y[i]].push_back({na[z[i]],0});
		}
		if(x[i]==2){
			p[na[y[i]]].push_back({na[z[i]],1});
		}
		if(x[i]==4){
			p[na[z[i]]].push_back({na[y[i]],1});
		}
	}
	for(ll i=1;i<=n;i++){//计算入度 
		if(na[i]!=i)continue;
		for(ll j=0;j<p[i].size();j++){
			rd[p[i][j].root]++;
		}
	}
	topu();//拓扑 
	return 0;
}

记录

2024/10/20 17:26
加载中...