HDU 2242 (Tarjan双连通缩点+树形DP)
2015-09-08 00:20
573 查看
n个点m条无向边,要去一条边得到两个连通分支,所以要去掉的一定是桥。先跑一边Tarjan找到所有的桥,然后双连通缩点,所有的双连通分量所成一个点,再用桥连接,得到一棵树。然后跑一遍树形DP。
代码:
代码:
// Header. #include <algorithm> #include <iostream> #include <sstream> #include <cstring> #include <cstdio> #include <vector> #include <string> #include <bitset> #include <queue> #include <cmath> #include <ctime> #include <set> #include <map> using namespace std; // Macro typedef long long LL; #define TIME cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s." << endl; #define IN freopen("/Users/apple/input.txt", "r", stdin); #define OUT freopen("/Users/apple/out.txt", "w", stdout); #define mem(a, n) memset(a, n, sizeof(a)) #define rep(i, n) for(int i = 0; i < (n); i ++) #define repD(i, n) for(int i = (n); i; i --) #define REP(i, t, n) for(int i = (t); i < (n); i ++) #define REPD(i, t, n) for(int i = (n); i > (t); i --) #define FOR(i, t, n) for(int i = (t); i <= (n); i ++) #define FORD(i, t, n) for(int i = (n); i >= (t); i --) #define ALL(v) v.begin(), v.end() #define Min(a, b) a = min(a, b) #define Max(a, b) a = max(a, b) #define put(a) printf("%d\n", a) #define ss(a) scanf("%s", a) #define si(a) scanf("%d", &a) #define sii(a, b) scanf("%d%d", &a, &b) #define siii(a, b, c) scanf("%d%d%d", &a, &b, &c) #define VI vector<int> #define pb push_back #define x first #define y second const int inf = 0x3f3f3f3f, N = 1e4 + 5, MOD = 1e9 + 7; // Macro end int T, cas = 0; int n, m, ne, ans, all, top, bch, dfsNum; int a , head , dfn , low , tree , sum , col , stack ; vector<pair<int, int> > brige; bool vis ; struct edge { int v, next; }e[10 * N]; // Imp void addEdge(int u, int v) { e[ne].v = v, e[ne].next = head[u], head[u] = ne ++; } void Tarjan(int u, int fa) { dfn[u] = low[u] = dfsNum ++; vis[u] = 1; stack[top++] = u; int flag = 0; for(int i = head[u]; i != -1; i = e[i].next) { int v = e[i].v; if(v == fa && !flag) { flag = 1; continue; } if(!vis[v]) { Tarjan(v, u); Min(low[u], low[v]); } else if(col[v] == -1) Min(low[u], dfn[v]); if(dfn[u] < low[v]) brige.pb(make_pair(u, v)); } if(low[u] == dfn[u]) { while(stack[top-1] != u) col[stack[--top]] = bch, sum[bch] += a[stack[top]]; top --; sum[bch] += a[stack[top]]; col[u] = bch ++; } } void build() { int sz = brige.size(); rep(i, sz) { int u = brige[i].x, v = brige[i].y; e[ne].v = col[v], e[ne].next = tree[col[u]]; tree[col[u]] = ne ++; e[ne].v = col[u], e[ne].next = tree[col[v]]; tree[col[v]] = ne ++; } } int dfs(int u) { int tmp = sum[u]; vis[u] = 1; for(int i = tree[u]; i != -1; i = e[i].next) { if(!vis[e[i].v]) tmp += dfs(e[i].v); } Min(ans, abs(all - 2 * tmp)); return tmp; } void init() { mem(tree, -1); mem(head, -1); mem(col, -1); mem(vis, 0); mem(sum, 0); brige.clear(); bch = top = all = ne = dfsNum = 0; } int main(){ #ifdef LOCAL IN // OUT #endif while(sii(n, m) != EOF) { init(); rep(i, n) si(a[i]), all += a[i]; int u, v; rep(i, m) { sii(u, v); addEdge(u, v), addEdge(v, u); } Tarjan(0, 0); if(bch != 1) { build(); mem(vis, 0); ans = inf; dfs(0); put(ans); } else puts("impossible"); } return 0; }
相关文章推荐
- makefile教程
- C语言函数指针和Objective-c中的block
- 设计模式—模板模式(Template Pattern)
- 每日更新博客文章
- 迟滞变化
- POJ 1180 Batch Scheduling
- 业火的向日葵 新娘大作战
- CDOJ 1104 求两个数列的子列的交集 查询区间小于A的数有多少个 主席树
- 官方demo 创建一个excel
- VC++6.0调试篇:定位临界区(critical section)导致的死锁
- 关于ExtJs4的Grid带 查询 参数 分页(baseParams-->extraParams)
- C++实现中缀表达式转前、后缀
- android上实现multi-part上传
- [转载]IDEA新建web项目
- Java面试题
- Letter Combinations of a Phone Number
- Spring MVC 前端ajax传入多个参数(包含数组)后端controller的一次性接收
- 20150906全志a33上调通rtl8188eus的过程(sina33)
- 数据结构Java实现06----中缀表达式转换为后缀表达式
- tar 命令