Card Game

每个牌背面的数字朝正面的数字连一条有向边

则题目变为问你最少翻转多少次 能使得每个数字的入度不超过1

首先判断图中每个连通块是不是树或者基环树 因为只有树或者基环树能使得每个点的入度不超过1

判的话就直接判断边的数量与点的数量之间的大小关系如果边数<=点数则可行

对于树 我们进行两次dp 第一次dp出以一个点为根需要翻转的次数 第二次就可以转移出以每个点为根需要翻转的次数

对于基环树 我们先看环里面需要翻转的次数 再判断环之外需要翻转的次数 环之外的方向是确定的 很好判断

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int, int> PII;
const ll mod = ;
ll powmod(ll a, ll b)
{
ll res = ;
a %= mod;
assert(b >= );
for (; b; b >>= )
{
if (b & )
{
res = res * a % mod;
}
a = a * a % mod;
}
return res;
}
ll gcd(ll a, ll b)
{
return b ? gcd(b, a % b) : a;
}
// head const int N = ;
int n, m, u, v, T, mt[N], hs[N], _;
vector<PII> e[N];
VI vec[N];
int vis[N], f[N], se[N], q[N], dp[N], pre[N], deg[N], fa[N];
PII chke[N];
int find(int u)
{
return f[u] == u ? u : f[u] = find(f[u]);
}
void solve()
{
n = ;
T++;
rep(i, , m + )
{
scanf("%d%d", &u, &v);
if (mt[u] != T) //离散化
{
mt[u] = T, hs[u] = n++;
}
if (mt[v] != T)
{
mt[v] = T, hs[v] = n++;
}
u = hs[u];
v = hs[v];
chke[i] = mp(u, v); //记录每条边
}
rep(i, , n) //初始化
e[i].clear(), vis[i] = , f[i] = i, vec[i].clear(), se[i] = ;
rep(i, , m + )
{
u = chke[i].fi, v = chke[i].se;
f[find(u)] = find(v); //一个连通块的点属于一个father
e[u].pb(mp(v, i)); //建边 i为正表示该边是反向与原来相反
e[v].pb(mp(u, -i));
}
rep(i, , n) //把一个连通块的点放到father的vector中
vec[find(i)].pb(i);
rep(i, , m + )
{
u = chke[i].fi, v = chke[i].se;
se[find(u)]++; //统计每个连通块中边的数量
}
int ans = , ans2 = ;
rep(i, , n)
{
if (find(i) != i) //每个连通块只会枚举一次
{
continue;
}
if (se[i] > SZ(vec[i])) //如果边数大于点数 则不是基环树也不是树 答案不存在
{
puts("-1 -1");
return;
}
if (se[i] < SZ(vec[i]))
{
//如果是树的话 dp两次 第一次dp出以0为根的翻转次数 第二次dp出全部点的翻转次数
int s = 1e9, s2 = ;
dp[i] = ;
int t = ;
q[] = i;
fa[i] = -;
rep(j, , t)
{
u = q[j];
for (auto p : e[u])
{
int v = p.fi;
if (v != fa[u])
{
fa[q[t++] = v] = u, pre[v] = p.se > , dp[i] += pre[v];
}
}
}
rep(j, , t)
{
u = q[j];
if (pre[u] == )
{
dp[u] = dp[fa[u]] - ;
}
else
{
dp[u] = dp[fa[u]] + ;
}
}
rep(j, , t)
s = min(s, dp[q[j]]); //当前树所需要的最少翻转次数
rep(j, , t)
if (dp[q[j]] == s)
{
s2++; //统计有多少个方案数
}
ans = ans + s;
ans2 = (ll)ans2 * s2 % mod;
}
if (se[i] == SZ(vec[i])) //基环树
{
int s = ;
for (auto u : vec[i])
{
deg[u] = SZ(e[u]); //统计每一个点的出度
}
int t = ;
for (auto u : vec[i])
if (deg[u] == )
{
q[t++] = u;
}
rep(j, , t)
{
u = q[j];
for (auto p : e[u])
{
int v = p.fi;
if (deg[v] <= )
{
continue;
}
if (p.se < )
{
s++;
}
--deg[v];
if (deg[v] == )
{
q[t++] = v;
}
}
}
int rt = -;
for (auto u : vec[i])
if (deg[u] == )
{
rt = u;
break;
}
int pree = 1e9, cnt = , u = rt, s3 = ;
while ()
{
for (auto p : e[u])
if (deg[p.fi] == && p.se + pree != )
{
s3 += p.se < ;
cnt++;
pree = p.se;
u = p.fi;
break;
}
if (u == rt)
{
break;
}
}
s3 = min(s3, cnt - s3); //环中的翻转最少次数是确定的
s += s3; //环外的方向是确定的 环外需要翻转的次数加上环中翻转的次数
ans += s;
if (s3 == cnt - s3)
{
ans2 = ans2 * % mod;
}
}
}
printf("%d %d\n", ans, ans2);
}
int main()
{
for (scanf("%d", &_); _; _--)
{
scanf("%d", &m);
solve();
}
}

//Card Game

Hdu第八场 树形dp+基环树的更多相关文章

  1. HDU 4514 - 湫湫系列故事——设计风景线 - [并查集判无向图环][树形DP求树的直径]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4514 Time Limit: 6000/3000 MS (Java/Others) Memory Li ...

  2. hdu5293 Tree chain problem 树形dp+线段树

    题目:pid=5293">http://acm.hdu.edu.cn/showproblem.php?pid=5293 在一棵树中,给出若干条链和链的权值.求选取不相交的链使得权值和最 ...

  3. 【BZOJ-1040】骑士 树形DP + 环套树 + DFS

    1040: [ZJOI2008]骑士 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3312  Solved: 1269[Submit][Status ...

  4. 浅谈关于树形dp求树的直径问题

    在一个有n个节点,n-1条无向边的无向图中,求图中最远两个节点的距离,那么将这个图看做一棵无根树,要求的即是树的直径. 求树的直径主要有两种方法:树形dp和两次bfs/dfs,因为我太菜了不会写后者这 ...

  5. 树形DP 学习笔记(树形DP、树的直径、树的重心)

    前言:寒假讲过树形DP,这次再复习一下. -------------- 基本的树形DP 实现形式 树形DP的主要实现形式是$dfs$.这是因为树的特殊结构决定的——只有确定了儿子,才能决定父亲.划分阶 ...

  6. HDU 5293 Annoying problem 树形dp dfs序 树状数组 lca

    Annoying problem 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 Description Coco has a tree, w ...

  7. POJ 2342 &&HDU 1520 Anniversary party 树形DP 水题

    一个公司的职员是分级制度的,所有员工刚好是一个树形结构,现在公司要举办一个聚会,邀请部分职员来参加. 要求: 1.为了聚会有趣,若邀请了一个职员,则该职员的直接上级(即父节点)和直接下级(即儿子节点) ...

  8. HDU 1520 Anniversary party [树形DP]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520 题目大意:给出n个带权点,他们的关系可以构成一棵树,问从中选出若干个不相邻的点可能得到的最大值为 ...

  9. hdu 1520Anniversary party(简单树形dp)

    Anniversary party Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

随机推荐

  1. Winform非UI线程更新UI界面的各种方法小结

    我们知道只有UI线程才能更新UI界面,其他线程访问UI控件被认为是非法的.但是我们在进行异步操作时,经常需要将异步执行的进度报告给用户,让用户知道任务的进度,不至于让用户误认为程序“死掉了”,特别是对 ...

  2. Ubuntu16.04系统Tensorflow源码安装

    最近学习Tensorflow,记录一下安装过程.目前安装的是CPU版的 1.下载tensorflow源码 tensorflow是个开源库,在github上有源码,直接在上面下载.下载地址:https: ...

  3. 对js原型对象、实例化对象及prototype属性的一些见解

    什么是原型对象? 请看下面的代码,我们以各种姿势,创建了几个方法! function fn1() { } var fn2 = function () { } var fn3 = new Functio ...

  4. vue中局部封装axios

    Vue中局部配置axios 'use strict' import axios from 'axios'; import { Loading } from 'element-ui'; export c ...

  5. git 提交项目到远程仓库,简单实现忽略 node_modules文件

    在项目根目录中创建 .gitignore文件 在文件中添加你要忽略的文件 .DS_Store node_modules /dist # local env files .env.local .env. ...

  6. cisco路由的ip静态路由添加(二)

    路由器Corp 配置Corp(config)#ip route 192.168.20.0 255.255.255.0 10.1.3.2 150 Corp(config)#ip route 192.16 ...

  7. kafka的错误日志log监控

    例如:需要监控下面的日志中的error 日志文件是这个 /data1/confluent-5.2.2/logs/connect/kafka-connect.log 1/ 参考上一篇安装zabbix_a ...

  8. 手把手教你用 Strace 诊断问题

    早些年,如果你知道有个 strace 命令,就很牛了,而现在大家基本都知道 strace 了,如果你遇到性能问题求助别人,十有八九会建议你用 strace 挂上去看看,不过当你挂上去了,看着满屏翻滚的 ...

  9. 大数据之Hadoop完全分布式集群搭建

    1.准备阶段 1.1.新建三台虚拟机 Hadoop完全分市式集群是典型的主从架构(master-slave),一般需要使用多台服务器来组建.我们准备3台服务器(关闭防火墙.静态IP.主机名称).如果没 ...

  10. C++学习 之 继承(笔记)

    1.继承基础: 继承就像是生物里的遗传与变异,即派生类(子代)从基类(父代)那里继承基类的某些特性(遗传),并在此基础上拥有自己的特性(变异). C++派生语法: class Base//定义一个基类 ...