题目大意:给一张$n(n\leqslant2000)$个点的无向图,给所有边定向,使定向之后存在最多的有序点对$(a,b)$满足从$a$能到$b$

题解:先把边双缩点,因为这里面的点一定两两可达。

根据网上题解得知,最优解一定长这样:存在一个点$s$,使得对于任意其他点$t$,要么$s$可以到$t$,要么$t$可以到$s$,就把$s$作为根。(出题人的题解也没给出解答,就感性理解)

所以$s$的每一个子树内的边要么都朝向$s$,要么都远离$s$

然后可以枚举哪个点作为根,记$w_i$第$i$个双联通分量的大小,$sz_i$为以第$i$个双联通分量为根的子树大小,每个子树内的点在子树内的贡献为$w_i(sz_i-w_i)$,令$P$为朝向根的节点的$sz$和,过根的贡献为$P(n-w_s-P)$,所以只需要让$P$与$(n-w_s-P)$尽可能接近即可,可以用背包来实现

卡点:

C++ Code:

#include <cstdio>
#include <bitset>
#define maxn 2010
#define maxm (maxn * maxn)
inline int min(int a, int b) {return a < b ? a : b;}
inline int max(int a, int b) {return a > b ? a : b;} int n, m; namespace Graph {
int head[maxn], cnt = 1;
struct Edge {
int to, nxt;
} e[maxm];
inline void addE(int a, int b) {
e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
e[++cnt] = (Edge) {a, head[b]}; head[b] = cnt;
} int w[maxn];
int DFN[maxn], low[maxn], idx;
int S[maxn], top, res[maxn], scc;
void tarjan(int u, int fa = 0) {
DFN[u] = low[u] = ++idx;
S[++top] = u;
int v;
for (int i = head[u]; i; i = e[i].nxt) {
v = e[i].to;
if (v != fa) {
if (!DFN[v]) {
tarjan(v, u);
low[u] = min(low[u], low[v]);
} else low[u] = min(low[u], DFN[v]);
}
}
if (DFN[u] == low[u]) {
scc++;
do {
v = S[top--];
w[res[v] = scc]++;
} while (u != v);
}
}
} long long ans;
namespace Tree {
int head[maxn], cnt;
struct Edge {
int to, nxt;
} e[maxn << 1];
inline void addE(int a, int b) {
e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
e[++cnt] = (Edge) {a, head[b]}; head[b] = cnt;
}
using Graph::res;
using Graph::w;
using Graph::scc; void init(int n, int m) {
for (int i = 1; i <= n; i++) if (!Graph::DFN[i]) Graph::tarjan(i);
for (int i = 2; i <= Graph::cnt; i += 2) {
int u = Graph::e[i ^ 1].to, v = Graph::e[i].to;
if (res[u] != res[v]) addE(res[u], res[v]);
}
} int sz[maxn];
int __ans, sumsz;
std::bitset<maxn / 2> B;
#define ans __ans
void dfs(int u, int fa = 0) {
sz[u] = w[u];
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v != fa) {
dfs(v, u);
sz[u] += sz[v];
}
}
ans += sz[u] * w[u];
}
int calc(int u) {
B.reset();
B[0] = true;
ans = 0; dfs(u);
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
B |= B << sz[v];
}
for (int i = sumsz - w[u] >> 1; i; i--) if (B[i]) return ans + i * (sumsz - w[u] - i);
return ans;
}
#undef ans int q[maxn], h, t;
bool vis[maxn];
void solve(int u) {
vis[q[h = t = 0] = u] = true;
int res = 0;
sumsz = 0;
while (h <= t) {
int u = q[h++];
sumsz += w[u];
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (!vis[v]) vis[q[++t] = v] = true;
}
}
for (int i = 0; i <= t; i++) res = max(res, calc(q[i]));
ans += res;
}
void work() {
for (int i = 1; i <= scc; i++) if (!vis[i]) solve(i);
}
} int main() {
scanf("%d%d", &n, &m);
for (int i = 0, a, b; i < m; i++) {
scanf("%d%d", &a, &b);
Graph::addE(a, b);
}
Tree::init(n, m);
Tree::work();
printf("%lld\n", ans);
return 0;
}

  

[CF475E]Strongly Connected City 2的更多相关文章

  1. cf475B Strongly Connected City

    B. Strongly Connected City time limit per test 2 seconds memory limit per test 256 megabytes input s ...

  2. codeforces B. Strongly Connected City(dfs水过)

    题意:有横向和纵向的街道,每个街道只有一个方向,垂直的街道相交会产生一个节点,这样每个节点都有两个方向, 问是否每一个节点都可以由其他的节点到达.... 思路:规律没有想到,直接爆搜!每一个节点dfs ...

  3. Codeforces 475 B Strongly Connected City【DFS】

    题意:给出n行m列的十字路口,<代表从东向西,>从西向东,v从北向南,^从南向北,问在任意一个十字路口是否都能走到其他任意的十字路口 四个方向搜,搜完之后,判断每个点能够访问的点的数目是否 ...

  4. Codeforces-475B Strongly Connected City

    仅仅用推断最外层是不是回路  假设是   则每两个点之间连通 #include<iostream> #include<algorithm> #include<cstdio ...

  5. PTA Strongly Connected Components

    Write a program to find the strongly connected components in a digraph. Format of functions: void St ...

  6. algorithm@ Strongly Connected Component

    Strongly Connected Components A directed graph is strongly connected if there is a path between all ...

  7. Strongly connected(hdu4635(强连通分量))

    /* http://acm.hdu.edu.cn/showproblem.php?pid=4635 Strongly connected Time Limit: 2000/1000 MS (Java/ ...

  8. 【CF913F】Strongly Connected Tournament 概率神题

    [CF913F]Strongly Connected Tournament 题意:有n个人进行如下锦标赛: 1.所有人都和所有其他的人进行一场比赛,其中标号为i的人打赢标号为j的人(i<j)的概 ...

  9. HDU 4635 Strongly connected (Tarjan+一点数学分析)

    Strongly connected Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) ...

随机推荐

  1. 【ospf-vlink虚拟连接】

    根据项目需求,搭建好如下拓扑图 配置rt1的环回 口地址及g0/0/0的ip地址 配置rt1的ospf 配置rt2的环回口地址和g0/0/1及g0/0/0的ip地址 \ 配置rt2的ospf 同理,配 ...

  2. QQ群排名霸屏技术居然是这样简单

    最近做了一些收费的QQ群,收多少钱,一块钱的入门费,也就是说进入我的QQ群必须要1块钱的会费. 我的QQ群主要是干嘛呢,放些电影,比如说市面上电影院,正在播放的,最新最热门的,火爆的一些电影. 先前呢 ...

  3. JS 红包随机

    微信随机红包,指定金额指定用户,随机发送红包 var moneys = new Array(); var moneyTotal = 0; function rand(obj){ if(obj.size ...

  4. hadoop搭建----centos免密码登录、修改hosts文件

    分布式系统在传输数据时需要多台电脑免密码登录 如:A(192.168.227.12)想ssh免密码登录到B(192.168.227.12),需要把A的公钥文件(~/.ssh/id_rsa.pub)里内 ...

  5. Python学习笔记:第一天python基础

    目录 1. python简介 2. python的安装 3. 编写第一个helloword 4. 变量和常量 5. 数据类型 6. 输入 7. if语句 1. python简介 python是在198 ...

  6. C语言实现计算二进制数字1的个数

    #include<stdio.h> #include<stdlib.h> int print_one_bits01(unsigned int value){ //0000 11 ...

  7. JAVA 反射之Method

    ★ Method没有构造器,只能通过Class获取. 重点方法: class.getDeclaredMethods():获取所有方法. class.getDeclaredMethod(String n ...

  8. Intellij 出现“Usage of API documented as @since 1.4+”的解决办法

    https://blog.csdn.net/wust_lh/article/details/73277185

  9. 一起来学习Shell脚本

    Shell脚本 Shell脚本(shell script),是一种为shell编写的脚本程序. 大家所说的shell通常都是指的shell脚本,但其实shell与shell脚本是两个不同的概念.由于习 ...

  10. 基于Ubuntu Server 16.04 LTS版本安装和部署Django之(一):安装Python3-pip和Django

    近期开始学习基于Linux平台的Django开发,想配置一台可以发布的服务器,经过近一个月的努力,终于掌握了基于Apache和mod-wsgi插件的部署模式,自己也写了一个教程,一是让自己有个记录,二 ...