题目大意:给一张$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. Hadoop(14)-MapReduce框架原理-切片机制

    1.FileInputFormat切片机制 切片机制 比如一个文件夹下有5个小文件,切片时会切5个片,而不是一个片 案例分析 2.FileInputFormat切片大小的参数配置 源码中计算切片大小的 ...

  2. DJANGO2.0 关联表的必填 ON_DELETE

    DJANGO2.0 关联表的必填 ON_DELETE 参数的含义 - BUXIANGHEJIU 的博客 - CSDN 博客 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blo ...

  3. C语言实现简易扫雷

    首先,写代码之前要将整体思路写出来: 扫雷游戏:1.需要两个二维数组,一个用来展示,一个用来放雷; 2.整体骨架在代码中都有注释说明; 3.游戏难度比较简单,适合初学者观看,如果有大佬看明白,可以指点 ...

  4. 博弈dp 以I Love this Game! POJ - 1678 为例

    写在前面的话 知识基础:一些基础的博弈论的方法,动态规划的一些知识 前言:博弈论就是一些关于策略或者游戏之间的最优解,动态规划就是对于一些状态之间转移的一些递推式(or 递归),dp分为很多很多种,比 ...

  5. Linux系统下安装rz/sz命令

    执行命令 yum install -y lrzsz rz -be本地上传文件到服务器

  6. Odoo8中安装新模块找不到的问题

    为了要让系统识别出新的模块,我们需要打开用户的技术特性选项,具体在    左侧栏目->用户->administrator,  将技术特性勾选上,刷新.  然后左侧栏目->模块下面就会 ...

  7. VS中的一些标记

    1.//ToDO:此标记运行时会显示在任务列表窗口中.

  8. 3、Java并发编程:Thread类的使用

    Java并发编程:Thread类的使用 在前面2篇文章分别讲到了线程和进程的由来.以及如何在Java中怎么创建线程和进程.今天我们来学习一下Thread类,在学习Thread类之前,先介绍与线程相关知 ...

  9. javascript对象转为字符串

    function getStringTime(time){ //年 year = time.getFullYear(); //月 month = time.getMonth() if(String(m ...

  10. 【APUE】Chapter3 File I/O

    这章主要讲了几类unbuffered I/O函数的用法和设计思路. 3.2 File Descriptors fd本质上是非负整数,当我们执行open或create的时候,kernel向进程返回一个f ...