zoukankan      html  css  js  c++  java
  • [洛谷P3387]【模板】缩点

    题目大意:给你一个有向图,让你找一条路径,使得该路径点权之和最大,如果重复经过只算一次。问最大是多少?

    解题思路:对每个强连通分量,如果到了某一个点,必然要把这里的所有点走一遍,和才会最大(废话)。

    于是我们缩点。

    然后暴力、拓扑+DP貌似都行。

    然后我Tarjan+暴力就过了(暴力出奇迹~(≧▽≦)/~)

    C++ Code:

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<vector>
    #define N 100005
    #define reg register
    using namespace std;
    struct edge{
    	int from,to,nxt;
    }e[10*N<<1];
    int head[N],n,m,low[N],dfn[N],cnt,stack[N],top,ltfl,ys[N],ans,f[N],a[N];
    bool vis[N];
    vector<int>v[N];
    inline int readint(){
    	char c=getchar();
    	bool b=false;
    	for(;!isdigit(c);c=getchar())b=c=='-';
    	int d=0;
    	for(;isdigit(c);c=getchar())
    	d=(d<<3)+(d<<1)+(c^'0');
    	return b?-d:d;
    }
    inline int min(int a,int b){return a<b?a:b;}
    inline int max(int a,int b){return a>b?a:b;}
    void tarjan(int now){
    	dfn[now]=low[now]=++cnt;
    	vis[stack[++top]=now]=true;
    	for(reg int i=head[now];i;i=e[i].nxt)
    	if(!dfn[e[i].to]){
    		tarjan(e[i].to);
    		low[now]=min(low[now],low[e[i].to]);
    	}else
    	if(vis[e[i].to])low[now]=min(low[now],dfn[e[i].to]);
    	if(low[now]==dfn[now]){
    		int v;
    		f[++ltfl]=0;
    		do{
    			v=stack[top--];
    			::v[ltfl].push_back(v);
    			ys[v]=ltfl;
    			vis[v]=false;
    			f[ltfl]+=a[v];
    		}while(v!=now);
    	}
    }
    void dfs(int now,int s){
    	vis[now]=true;
    	for(reg int i=v[now].size()-1;i>=0;--i){
    		for(reg int j=head[v[now][i]];j;j=e[j].nxt)
    		if(!vis[ys[e[j].to]])dfs(ys[e[j].to],s+f[ys[e[j].to]]);
    	}
    	vis[now]=false;
    	ans=max(ans,s);
    }
    int main(){
    	ltfl=0;
    	memset(head,0,sizeof head);
    	n=readint(),m=readint();
    	for(reg int i=1;i<=n;++i)a[i]=readint();
    	for(reg int i=1;i<=m;++i){
    		int u=readint(),v=readint();
    		e[i]=(edge){u,v,head[u]};
    		head[u]=i;
    	}
    	memset(vis,0,sizeof vis);
    	top=0;
    	memset(low,0,sizeof low);
    	memset(dfn,0,sizeof dfn);
    	for(reg int i=1;i<=n;++i)
    	if(!dfn[i]){
    		tarjan(i);
    	}
    	memset(vis,0,sizeof vis);
    	ans=0;
    	for(reg int i=1;i<=ltfl;++i)
    	dfs(i,f[i]);
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    【模板】对拍程序
    【洛谷比赛】Agent1
    【NOIP2017】宝藏
    【NOIP2017】逛公园
    【NOIP2016】换教室
    【NOIP模拟】挖宝藏
    【NOIP模拟】健美猫
    【NOIP2014】飞扬的小鸟
    【NOIP2015】子串
    【CQOI2007】余数求和
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/7729499.html
Copyright © 2011-2022 走看看