HAOI2010 软件安装
一开始我以为这道题是一个比较正常的分组背包,只不过原来做的题目的限制条件是数目,这次是有体积(软件所占空间)的限制,但是两者好像没什么差异……
于是我就仿着正常的分组背包写了一下,然后过了样例。我才不会告诉你我一开始结果全是0,因为我写错了
交上去一看只有10分……
回来发现原来这题并没有说是一棵树……orz,那我们来看一看每一个环,每个环里面所有的软件要么全选,要么全不选,所以直接看成一个强连通分量缩点,把体积和价值都合起来即可。就像炉石那张融合所以我们缩点,之后把所有入度为0的点向虚拟节点连边,之后开始正常DP。但是我一开始发现建出来的图是反的,这样就行不成树了。不过想起了tarjan求强连通分量的时候,因为我把树建成了有向图,所以肯定原来的起点现在还应该是起点,就把建图反了过来,之后就神奇的AC啦!
看一下代码。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<set> #include<queue> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') using namespace std; typedef long long ll; const int M = 1005; const int INF = 1000000009; const ll mod = 1e9+7; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } struct node { int next,to,from; }e[M<<1]; int m,n,dp[M][M],v[M],x,y,head[M],ecnt,size[M],w[M],dfn[M],scc[M],idx,low[M],stack[M],top,cnt; int rdeg[M],tot; bool vis[M]; void add(int x,int y) { e[++ecnt].to = y; e[ecnt].next = head[x]; e[ecnt].from = x; head[x] = ecnt; } void tarjan(int x) { low[x] = dfn[x] = ++idx; stack[++top] = x,vis[x] = 1; for(int i = head[x];i;i = e[i].next) { if(!dfn[e[i].to]) tarjan(e[i].to),low[x] = min(low[x],low[e[i].to]); else if(vis[e[i].to]) low[x] = min(low[x],dfn[e[i].to]); } if(low[x] == dfn[x]) { int p; cnt++; while((p = stack[top--])) { scc[p] = cnt,vis[p] = 0,v[cnt] += v[p],w[cnt] += w[p]; if(p == x) break; } } } void rebuild() { rep(i,1,ecnt) { int r1 = scc[e[i].from],r2 = scc[e[i].to]; if(r1 != r2) add(r2,r1),rdeg[r1]++; } rep(i,n+1,cnt) { dp[i][0] = v[i]; if(!rdeg[i]) add(0,i); } } void dfs(int x,int fa) { for(int i = head[x];i;i = e[i].next) { int t = e[i].to; if(t == fa) continue; dfs(t,x); per(j,m,1) { rep(p,0,j-w[t]) dp[x][j] = max(dp[x][j],dp[x][j-p-w[t]] + dp[t][p]); } //rep(j,0,m) printf("%d ",dp[x][j]);enter; //printf("#%d %d\n",x,dp[x][0]); } } int main() { n = read(),m = read(); rep(i,1,n) w[i] = read(); rep(i,1,n) v[i] = read(); rep(i,1,n) { x = read(); if(x != 0) add(i,x); } cnt = n,tot = ecnt; rep(i,1,n) if(!dfn[i]) tarjan(i); rebuild(); //rep(i,tot+1,ecnt) printf("%d %d\n",e[i].from,e[i].to); dfs(0,0); printf("%d\n",dp[0][m]); return 0; }
当你意识到,每个上一秒都成为永恒。