[Jsoi2010]连通数

[Jsoi2010]连通数

先Tarjan缩点,然后建反图拓扑看每一个点可以由哪里经过,用到bitset定义zt状态压缩一下,拓扑图中x->y :则表示y可以到达x,所以zt[y]=zt[y]|zt[x]就知道了y的,然后在for一下每个点及其所到达的点, Cgema算出两两乘积得出ans。

 

  1 #define MAXN 2010UL
  2 
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<queue>
  6 #include<iostream>
  7 #define MIN(a,b) (a)<(b)?(a):(b);
  8 using namespace std;
  9 
 10 int n,head[MAXN],cnt,id,sum;
 11 char key;
 12 int dfn[MAXN],low[MAXN],bel[MAXN],front[MAXN],ans;
 13 int sta[MAXN],tail;
 14 bool vis[MAXN];
 15 bool exi[MAXN][MAXN];
 16 int indu[MAXN];
 17 int be[MAXN];
 18 int ge[MAXN];
 19 queue<int>st;
 20 struct Node{
 21     int en,to;
 22 }eda[4000005];
 23 struct A{
 24     int en,to;
 25 }sg[2000005];
 26 int op=0;
 27 void Add(int x,int y){
 28     eda[++cnt].to=head[x];
 29     eda[cnt].en=y;
 30     head[x]=cnt;
 31 }
 32 void Add2(int x,int y){
 33     sg[++cnt].to=front[x];
 34     sg[cnt].en=y;
 35     front[x]=cnt;
 36 }
 37 int Tarjan(int x){
 38     dfn[x]=++id;
 39     low[x]=id;
 40     vis[x]=1;
 41     sta[++tail]=x;
 42     for(int i=head[x];i;i=eda[i].to){
 43         int y=eda[i].en;
 44         if(!dfn[y]){
 45             Tarjan(y);
 46             low[x]=MIN(low[x],low[y]);
 47         }else if(vis[y]){
 48             low[x]=MIN(dfn[y],low[x]);
 49         }
 50     }
 51     if(dfn[x]==low[x]){
 52         sum++;
 53         while(sta[tail]!=x&&tail){
 54             bel[sta[tail]]=sum;
 55             vis[sta[tail]]=0;
 56             tail--;
 57         }
 58         bel[sta[tail]]=sum;
 59         vis[sta[tail]]=0;
 60         tail--;
 61     }    
 62 }
 63 int dfs(int x){
 64 //    printf("%d\n",x);
 65     op+=ge[x];
 66     vis[x]=1;
 67     for(int i=front[x];i;i=sg[i].to){
 68         if(!vis[sg[i].en])
 69             dfs(sg[i].en);
 70     }
 71 }
 72 int main(){
 73     freopen("connect.in","r",stdin);
 74     freopen("connect.out","w",stdout);
 75     scanf("%d",&n);
 76     for(int i=1;i<=n;i++){
 77         for(int j=1;j<=n;j++){
 78             cin>>key;
 79             if(key=='1')    Add(i,j);
 80         }
 81     }
 82     for(int i=1;i<=n;i++){
 83         if(!dfn[i]) Tarjan(i);
 84     }    
 85     for(int i=1;i<=n;i++){
 86         ge[bel[i]]++;
 87         be[bel[i]]++;
 88         printf("%d belong to %d\n",i,bel[i]);
 89     }
 90     cnt=0;
 91     for(int i=1;i<=n;i++){
 92         for(int j=head[i];j;j=eda[j].to){
 93             int y=bel[eda[j].en];
 94     //        printf("%d -> %d\n",i,eda[j].en);
 95             if(!exi[bel[i]][y]&&y!=bel[i]){
 96                 Add2(y,bel[i]);
 97                 indu[bel[i]]++;
 98                 exi[bel[i]][y]=1;
 99             }
100         }
101     }
102     for(int i=1;i<=sum;i++){
103         printf("%d\n",indu[i]);
104         if(indu[i]==0) st.push(i);
105     } 
106     while(!st.empty()){
107         int u=st.front();
108         ans+=be[u]*ge[u];
109         for(int j=front[u];j;j=sg[j].to){
110             int y=sg[j].en;
111             indu[y]--;
112             ge[y]+=ge[u];
113              if(!indu[y]) st.push(y);
114         }
115         st.pop();
116     }
117     printf("%d",ans);
118 }
119 /*
120 5
121 01100
122 00101
123 00011
124 00000
125 00000
126 */
View Code

 

posted @ 2015-10-11 18:30 Lenicodes 阅读( ...) 评论( ...) 编辑 收藏
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用[1],dp[u][j]表示在u子树中选取恰好j个人时能获得的最大价值。而根据引用,该问题的时间复杂度为O(log2​104×nm)。 对于洛谷P2143 [JSOI2010] 巨额奖金问题,我们可以使用动态规划来解决。具体步骤如下: 1. 首先,我们需要构建一棵树来表示员工之间的关系。树的根节点表示公司的总经理,其他节点表示员工。每个节点都有一个权值,表示该员工的奖金金额。 2. 接下来,我们可以使用动态规划来计算每个节点的dp值。对于每个节点u,我们可以考虑两种情况: - 如果选择节点u,则dp[u][j] = dp[v][j-1] + value[u],其中v是u的子节点,value[u]表示节点u的奖金金额。 - 如果不选择节点u,则dp[u][j] = max(dp[v][j]),其中v是u的子节点。 3. 最后,我们可以通过遍历树的所有节点,计算出dp[u][j]的最大值,即为所求的巨额奖金。 下面是一个示例代码,演示了如何使用动态规划来解决洛谷P2143 [JSOI2010] 巨额奖金问题: ```python # 构建树的数据结构 class Node: def __init__(self, value): self.value = value self.children = [] # 动态规划求解最大奖金 def max_bonus(root, j): dp = [[0] * (j+1) for _ in range(len(root)+1)] def dfs(node): if not node: return for child in node.children: dfs(child) for k in range(j, 0, -1): dp[node.value][k] = max(dp[node.value][k], dp[node.value][k-1] + node.value) for child in node.children: for k in range(j, 0, -1): for l in range(k-1, -1, -1): dp[node.value][k] = max(dp[node.value][k], dp[node.value][k-l-1] + dp[child.value][l]) dfs(root) return dp[root.value][j] # 构建树 root = Node(1) root.children.append(Node(2)) root.children.append(Node(3)) root.children[0].children.append(Node(4)) root.children[0].children.append(Node(5)) root.children[1].children.append(Node(6)) # 求解最大奖金 j = 3 max_bonus_value = max_bonus(root, j) print("最大奖金为:", max_bonus_value) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值