poj3160 强连通+记忆化搜索

题意:有一张 n 点 m 边的有向无环图,每个点有各自的权值,可正可负,现在从一个点开始走,一直走到不能走到其他点为止,每经过一个点,可以选择获得或不获得它的权值,每个点可以走多次,但是权值只能获得一次,问最后最多能够获得多少权值。

每个点可以走多次,权值只能获得一次,路过的时候权值可以不获得,所以我们只需要考虑正的权值就行了。在一个强连通分量中的点的权值我们都能获得,所以先缩点,得到一个有向无环图,然后从每个入度为 0 的点开始DFS,累计得到的最大权值就行。

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stack>
  4 #include<queue>
  5 using namespace std;
  6
  7 const int maxn=3e4+5;
  8 const int maxm=2e5+5;
  9
 10 int head[2][maxn],point[2][maxm],nxt[2][maxm],size[2];
 11 int n,t,scccnt;
 12 int stx[maxn],low[maxn],scc[maxn],num[maxn],id[maxn],v[maxn];
 13 int dp[maxn];
 14 stack<int>S;
 15
 16 int max(int a,int b){return a>b?a:b;}
 17
 18 void init(){
 19     memset(head,-1,sizeof(head));
 20     size[0]=size[1]=0;
 21     memset(num,0,sizeof(num));
 22     memset(id,0,sizeof(id));
 23     memset(dp,-1,sizeof(dp));
 24 }
 25
 26 void add(int a,int b,int c=0){
 27     point[c][size[c]]=b;
 28     nxt[c][size[c]]=head[c][a];
 29     head[c][a]=size[c]++;
 30 }
 31
 32 void dfs(int s){
 33     stx[s]=low[s]=++t;
 34     S.push(s);
 35     for(int i=head[0][s];~i;i=nxt[0][i]){
 36         int j=point[0][i];
 37         if(!stx[j]){
 38             dfs(j);
 39             low[s]=min(low[s],low[j]);
 40         }
 41         else if(!scc[j]){
 42             low[s]=min(low[s],stx[j]);
 43         }
 44     }
 45     if(low[s]==stx[s]){
 46         scccnt++;
 47         while(1){
 48             int u=S.top();S.pop();
 49             scc[u]=scccnt;
 50             num[scccnt]+=v[u]>0?v[u]:0;
 51             if(s==u)break;
 52         }
 53     }
 54 }
 55
 56 void setscc(){
 57     memset(stx,0,sizeof(stx));
 58     memset(scc,0,sizeof(scc));
 59     t=scccnt=0;
 60     for(int i=1;i<=n;++i)if(!stx[i])dfs(i);
 61     for(int i=1;i<=n;++i){
 62         for(int j=head[0][i];~j;j=nxt[0][j]){
 63             int k=point[0][j];
 64             if(scc[i]!=scc[k]){
 65                 add(scc[i],scc[k],1);
 66                 id[scc[k]]++;
 67             }
 68         }
 69     }
 70 }
 71
 72 int dfs1(int s){
 73     if(~dp[s])return dp[s];
 74     int maxx=0;
 75     for(int i=head[1][s];~i;i=nxt[1][i]){
 76         int j=point[1][i];
 77         maxx=max(maxx,dfs1(j));
 78     }
 79     dp[s]=maxx+num[s];
 80     return dp[s];
 81 }
 82
 83 int main(){
 84     int m;
 85     while(scanf("%d%d",&n,&m)!=EOF){
 86         init();
 87         for(int i=1;i<=n;++i)scanf("%d",&v[i]);
 88         while(m--){
 89             int a,b;
 90             scanf("%d%d",&a,&b);
 91             a++;
 92             b++;
 93             add(a,b);
 94         }
 95         setscc();
 96         int ans=0;
 97         for(int i=1;i<=scccnt;++i){
 98             if(!id[i])ans=max(ans,dfs1(i));
 99         }
100         printf("%d\n",ans);
101     }
102     return 0;
103 }

时间: 2024-08-21 11:42:31

poj3160 强连通+记忆化搜索的相关文章

poj3592 强连通+记忆化搜索

题意:有一片 n*m 的矿地,每一格有矿.或这传送门.或者挡路岩石.除了岩石不能走以外,其他的格子都能够向右或向下走,走到一个非岩石的格子.对于每一个矿点,经过它就能得到它的所有矿石,而对于每一个传送门,你可以选择传送或者不传送,向右或向下继续走(传送门送达点也可能是岩石),按从上到下.从左到右的顺序对于每一个传送门给定一个传送点.问最多能够获得多少矿石. 对于这样一张图,我们能够发现,有一些点,由于传送门的存在,一定可以相互到达,那么这些点可以按强连通缩点,之后对于有向无环图就可以很轻松地用记

ZOJ3795 Grouping(强连通分量+缩点+记忆化搜索)

题目给一张有向图,要把点分组,问最少要几个组使得同组内的任意两点不连通. 首先考虑找出强连通分量缩点后形成DAG,强连通分量内的点肯定各自一组,两个强连通分量的拓扑序能确定的也得各自一组. 能在同一组的就是两个强连通分量在不同的从入度0到出度0的强连通分量的路径上. 那么算法很直观就能想到了,用记忆化搜索,d[u]表示从强连通分量u出发到出度为0的强连通分量最少要几个组(最多有几个点). 1 #include<cstdio> 2 #include<cstring> 3 #inclu

LightOJ1417 Forwarding Emails(强连通分量+缩点+记忆化搜索)

题目大概是,每个人收到信息后会把信息发给他认识的一个人如此下去,问一开始要把信息发送给谁这样看到信息的人数最多. 首先找出图中的SCC并记录每个SCC里面的点数,如果传到一个SCC,那么里面的人都可以看到信息. 然后SCC缩点后就形成DAG,直接记忆化搜索,d(u)搜索从u点出发开始传最多能传多少人. 最后就是找答案了. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namesp

BNU 20860——Forwarding Emails——————【强连通图缩点+记忆化搜索】

Forwarding Emails Time Limit: 1000ms Memory Limit: 131072KB This problem will be judged on UVA. Original ID: 1244264-bit integer IO format: %lld      Java class name: Main Prev Submit Status Statistics Discuss Next Type: None None Graph Theory 2-SAT

HDU 1513 Palindrome:LCS(最长公共子序列)or 记忆化搜索

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1513 题意: 给你一个字符串s,你可以在s中的任意位置添加任意字符,问你将s变成一个回文串最少需要添加字符的个数. 题解1(LCS): 很神奇的做法. 先求s和s的反串的LCS,也就是原串中已经满足回文性质的字符个数. 然后要变成回文串的话,只需要为剩下的每个落单的字符,相应地插入一个和它相同的字符即可. 所以答案是:s.size()-LCS(s,rev(s)) 另外,求LCS时只会用到lcs[i-

uva 1076 - Password Suspects(AC自动机+记忆化搜索)

题目链接:uva 1076 - Password Suspects 题目大意:有一个长度为n的密码,存在m个子串,问说有多少种字符串满足,如果满足个数不大于42,按照字典序输出. 解题思路:根据子串构建AC自动机,然后记忆化搜索,dp[i][u][s]表示第i个字符,在u节点,匹配s个子串. #include <cstdio> #include <cstring> #include <queue> #include <string> #include <

poj 1579(动态规划初探之记忆化搜索)

Function Run Fun Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17843   Accepted: 9112 Description We all love recursion! Don't we? Consider a three-parameter recursive function w(a, b, c): if a <= 0 or b <= 0 or c <= 0, then w(a, b

记忆化搜索,FatMouse and Cheese

1.从gird[0][0]出发,每次的方向搜索一下,每次步数搜索一下 for(i=0; i<4; i++) { for(j=1; j<=k; j++) { int tx=x+d[i][0]*j; int ty=y+d[i][1]*j; if(tx>=0&&tx<n&&ty>=0&&ty<n&&grid[x][y]<grid[tx][ty]) { int temp=memSearch(tx,ty); i

POJ1088(记忆化搜索)

经典记忆化搜索题目.当 从每个点一次进行搜索时要采用 记忆化搜索 #include"cstdio" #include"algorithm" using namespace std; const int MAXN=105; int g[MAXN][MAXN]; int t[MAXN][MAXN]; int maxn; int n,m; int by,bx; int ans; int dx[4]={1,0,-1,0}; int dy[4]={0,1,0,-1}; int