[刷题]HDU2242
来源:互联网 发布:java auth2.0开源框架 编辑:程序博客网 时间:2024/05/17 02:16
Problem Description
众所周知,HDU的考研教室是没有空调的,于是就苦了不少不去图书馆的考研仔们。Lele也是其中一个。而某教室旁边又摆着两个未装上的空调,更是引起人们无限YY。
一个炎热的下午,Lele照例在教室睡觉的时候,竟然做起了空调教室的美梦。
Lele梦到学校某天终于大发慈悲给某个教室安上了一个空调。而且建造了了M条通气管道,让整个教学楼的全部教室都直接或间接和空调教室连通上,构成了教室群,于是,全部教室都能吹到空调了。
不仅仅这样,学校发现教室人数越来越多,单单一个空调已经不能满足大家的需求。于是,学校决定封闭掉一条通气管道,把全部教室分成两个连通的教室群,再在那个没有空调的教室群里添置一个空调。
当然,为了让效果更好,学校想让这两个教室群里的学生人数尽量平衡。于是学校找到了你,问你封闭哪条通气管道,使得两个教室群的人数尽量平衡,并且输出人数差值的绝对值。
Input
本题目包含多组数据,请处理到文件结束。
每组测试第一行包含两个整数N和M(0
Output
对于每组数据,请在一行里面输出所求的差值。
如果不管封闭哪条管道都不能把教室分成两个教室群,就输出”impossible”。
Sample Input
4 31 1 1 10 11 22 34 31 2 3 50 11 22 3
Sample Output
01
Key1
边的双连通分量。首先是求分量,然后缩点。然后简单的树形DP即可。
要点是,它的图可以有重边。被坑了好久。
Code1
#include<algorithm>#include<iostream>#include<cstring>#include<vector>#include<cmath>#include<set>const int Maxn = 10000 + 23;using namespace std;class CutEdge {private: int N; int clk, pre[Maxn]; int DFS(int u, int f) { int lowu = pre[u] = ++clk; for (auto e = G[u].begin(); e != G[u].end(); ++e) { int v = *e; if (!pre[v]) { int lowv = DFS(v, u); lowu = min(lowu, lowv); if (lowv > pre[u]) { Cut[u].insert(v); Cut[v].insert(u); } } else if (pre[u] > pre[v]) { int cnt = 0; //重复边的处理 for (const auto &e : G[u]) if (e == v) ++cnt; if (cnt > 1 || v != f) { lowu = min(lowu, pre[v]); } } } return lowu; } //求边双联通部分 void DFS2(int u, int id) { ID[u] = id; for (const auto &v : G[u]) if (!ID[v]) { if (Cut[u].count(v)) { ++Num; G2[id].push_back(Num); G2[Num].push_back(id); DFS2(v, Num); } else DFS2(v, id); } }public: vector<int> G[Maxn]; set<int> Cut[Maxn]; //求边双联通部分 vector<int> G2[Maxn]; //缩点后的图(以ID为结点) int ID[Maxn]; //每个点所在的子图 int Num; //ID个数 void Clear(int n) { N = n; memset(ID, 0, sizeof(ID)); memset(pre, 0, sizeof(pre)); for (int i = 1; i <= N; ++i) { G[i].clear(); G2[i].clear(); Cut[i].clear(); } clk = 0; Num = 1; } void AddEdge(int u, int v) { G[u].push_back(v); G[v].push_back(u); } void Find() { for (int i = 1; i <= N; ++i) if (!pre[i]) DFS(i, -1); } //求边双联通部分 int BCC() { DFS2(1, Num); return Num; }};int N, M;int V[Maxn];int V2[Maxn];int DP[Maxn];bool vis[Maxn];CutEdge C;int DFS(int u) { vis[u] = true; DP[u] = V2[u]; for (const auto &v : C.G2[u]) { if (!vis[v]) DP[u] += DFS(v); } return DP[u];}int main() { ios::sync_with_stdio(false); while (cin >> N >> M) { memset(V2, 0, sizeof(V2)); memset(vis, 0, sizeof(vis)); memset(DP, 0, sizeof(DP)); C.Clear(N); for (int i = 1; i <= N; ++i) cin >> V[i]; int u, v; for (int i = 1; i <= M; ++i) { cin >> u >> v; C.AddEdge(++u, ++v); } C.Find(); C.BCC(); if (C.Num == 1) { cout << "impossible\n"; continue; } int sum = 0; for (int i = 1; i <= N; ++i) { sum += V[i]; V2[C.ID[i]] += V[i]; } DFS(1); int res = sum; for (int i = 1; i <= C.Num; ++i) { res = min(abs(sum - 2 * DP[i]), res); } cout << res << '\n'; } return 0;}
Key2
可以的优化是,其实在第一个DFS的时候,由于知道了桥的位置,可以在DFS的时候直接求出v以及v的子节点的和。那么在找到桥{u, v}的时候就直接顺便DP了。
Code2
#include<algorithm>#include<iostream>#include<cstring>#include<vector>#include<cmath>#include<set>const int Maxn = 10000+23;using namespace std;int N, M;int V[Maxn];int res,sum;class BCC {private: int N; int clk, pre[Maxn]; int DFS(int u, int f) { int &lowu = ID[u]; lowu= pre[u] = ++clk; for (auto e = G[u].begin(); e != G[u].end(); ++e) { int v = *e; if (!pre[v]) { int lowv = DFS(v, u); lowu = min(lowu, lowv); if (lowv > pre[u]) { ++Num; res = min(abs(sum - 2 * V[v]), res); } } else if (pre[u] > pre[v]) { int cnt = 0; //重复边的处理 for (const auto &e : G[u]) if (e == v) ++cnt; if (cnt > 1 || v != f) { lowu = min(lowu, pre[v]); } } /*else if (pre[u]>pre[v] && v != f) lowu = min(lowu, pre[v]);*/ } if(f!=-1) V[f] += V[u]; return lowu; }public: vector<int> G[Maxn]; int ID[Maxn]; int Num; void Clear(int n) { N = n; memset(ID, 0, sizeof(ID)); memset(pre, 0, sizeof(pre)); for (int i = 1; i <= N; ++i) { G[i].clear(); } clk = 0; Num = 1; } void AddEdge(int u, int v) { G[u].push_back(v); G[v].push_back(u); } int Find() { for (int i = 1; i <= N; ++i) if (!pre[i]) DFS(i, -1); return Num; }};BCC C;int main() { ios::sync_with_stdio(false); while (cin >> N >> M) { C.Clear(N); sum = 0; for (int i = 1; i <= N; ++i) { cin >> V[i]; sum += V[i]; } int u, v; for (int i = 1; i <= M; ++i) { cin >> u >> v; C.AddEdge(++u, ++v); } res = sum; if (C.Find() == 1) { cout << "impossible\n"; } else cout << res << '\n'; } return 0;}
阅读全文
1 0
- [刷题]HDU2242
- hdu2242
- hdu2242考研路茫茫——空调教室
- 我的点双连通模板(HDU2242)
- HDU2242 考研路茫茫——空调教室
- hdu2242 考研路茫茫——空调教室
- hdu2242考研路茫茫——空调教室
- HDU2242 考研路茫茫——空调教室
- hdu2242考研路茫茫——空调教室(边双连通,缩点,dfs)
- HDU2242 考研路茫茫——空调教室 (割桥 + dp)
- HDU2242 考研路茫茫——空调教室 解题报告【边双联通分量+树上dp】
- 刷题
- 刷题
- 刷题
- 刷题
- 刷题
- 刷题。。。
- 刷题
- IBM成功在一颗原子中存储数据:信用卡大小存储iTunes所有3500万首歌曲
- 谷歌气球项目再度换帅,曾被委以重任的 CEO 仅任职 6 个月
- Google云服务策略:不拼技术拼队友
- 传腾讯正寻求20亿美元新贷款,过去9个月已融资79.4亿美元
- java(7):内存泄露
- [刷题]HDU2242
- webstrom支持es6语法
- ubuntu16.04分区设置
- jQuery读取json文件
- 简单的c语言三子棋游戏(我写的第一个超过百行的程序,多有不足)
- 这个曾经发明“真·双卡双待”的芯片大佬展讯,决心挑战高通和联发科的高端芯片
- 搜索又出幺蛾子 百度搜狗因不合格医疗机构广告被罚款
- 传滴滴收购支付牌照,官方回应:无计划进入支付行业
- const和static的区别和用法