题目大意:给一张$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. ubuntu系統如何啟動root用戶登陸?

    之前分享過關於這個問題的文章,現在自己在分享一個關於這個問題的文章給大家.為了學習Linux,一氣之下把win10的換成了ubuntu的系統.安裝就不給大家介紹了(網上很多教程). 在我們安裝好之後, ...

  2. [转]JavaScript中的匿名函数及函数的闭包

    JavaScript中的匿名函数及函数的闭包  原文地址:http://www.cnblogs.com/wl0000-03/p/6050108.html 1.匿名函数 函数是JavaScript中最灵 ...

  3. HDU1209:Clock

    参考:https://blog.csdn.net/libin56842/article/details/8990530 https://blog.csdn.net/u011479875/article ...

  4. STL 一些常用的STL函数(持续更新

    先说一下  一边要用到算法的东西一般要加#include<algorithm>头文件 一.栈和队列 1 栈 :一种线性表 特点  后进先出 头文件  #include<stack&g ...

  5. C 二维指针难点详解。

    关于   指向二维数组的指针. int  a[2][3]; int *p; int (*p_1)[3]; 可以用p_1 = a ,但是不能用p = a : 因为此时数组a的数据类型是  int (* ...

  6. 一步一步构建手机WebApp开发——页面布局篇

    继上一篇:一步一步构建手机WebApp开发——环境搭建篇过后,我相信很多朋友都想看看实战案例,这一次的教程是页面布局篇,先上图: 如上图所示,此篇教程便是教初学者如何快速布局这样的页面.废话少说,直接 ...

  7. 给apk签名

    一.签名 把apk和签名文件放在jdk bin目录下,然后在jkd bin目录下执行以下代码: jarsigner -verbose -keystore xxx.keystore -signedjar ...

  8. 设置socket接收和发送超时的一种方式

    Linux环境设置Socket接收和发送超时: 须如下定义:struct timeval timeout = {3,0};  //设置发送超时setsockopt(socket,SOL_SOCKET, ...

  9. mysql 查询当月天数

    SELECT day(LAST_DAY('2018-02-01')) 思路: 先通过LAST_DAY() 查找当月最后一天,然后通过day()返回天数.

  10. 用jsp实现省市区三级联动下拉

    jsp+jquery实现省市区三级联动下拉 不少系统都需要实现省市区三级联动下拉,像人口信息管理.电子商务网站.会员管理等,都需要填写地址相关信息.而用ajax实现的无刷新省市区三级联动下拉则可以改善 ...