POJ3345
http://poj.org/problem?id=3345
大意:
大意是说现在有n个城市来给你投票,你需要至少拿到m个城市的赞成票。想要获得第i个城市的赞成需要花费w[i],有个条件就是某些城市是在其他某个城市的统治下的,当获得某个城市的赞成票后,那么他所统治的其他城市都会投票给你(不再需要花费),球最小花费
题解:
我们很容易看出这个统治关系组成了一个树的结构,就等于拿到i整个子树的所有节点的花费就是节点i的花费,求最后拿到>=m个节点的最小花费
我的状态也是按照题目要求设的,F[i]表示到目前为止得到i个城市的赞成的最小花费,然后进行树上DP。
F[i] = min{F[i-num[u]] + w[u]}
其中u表示当前所处的节点,num[u]表示节点u子树上节点数量
这里这样DP是会有问题的,就是我们不能在子节点的F值算出来后再算父节点的F值,否则就可能存在用子节点选择了的状态更新父节点选择的状态,也就是说在DFS时,只能先算父节点的F值,再进行dfs算子节点的
另外这里的F[i-num[u]]实际上只能是由节点u的已经算出的兄弟节点推到(就是说在考虑节点u加入时,他的父节点是不能被加入了的)
上面两个要求统一起来就是说计算父节点的F值(吧父节点加入),子节点的不可以先被计算出;计算子节点的F值时,父节点不可以先加入。解决办法就是另外开一个数组G[i][j],用来临时存放节点i往下递归前的结果,回溯时再更新
上面的F,G对应下面的DP,DP2
dfs1用来计算num数组,dfs2是DP过程,复杂度O(n^2)
- #include <map>
- #include <set>
- #include <stack>
- #include <queue>
- #include <cmath>
- #include <ctime>
- #include <vector>
- #include <cstdio>
- #include <cctype>
- #include <cstring>
- #include <cstdlib>
- #include <iostream>
- #include <algorithm>
- using namespace std;
- #define INF 1e9
- #define inf (-((LL)1<<40))
- #define lson k<<1, L, mid
- #define rson k<<1|1, mid+1, R
- #define mem0(a) memset(a,0,sizeof(a))
- #define mem1(a) memset(a,-1,sizeof(a))
- #define mem(a, b) memset(a, b, sizeof(a))
- #define FOPENIN(IN) freopen(IN, "r", stdin)
- #define FOPENOUT(OUT) freopen(OUT, "w", stdout)
- #define rep(i, a, b) for(int i = a; i <= b; i ++)
- template<class T> T CMP_MIN(T a, T b) { return a < b; }
- template<class T> T CMP_MAX(T a, T b) { return a > b; }
- template<class T> T MAX(T a, T b) { return a > b ? a : b; }
- template<class T> T MIN(T a, T b) { return a < b ? a : b; }
- template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
- template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b; }
- typedef __int64 LL;
- //typedef long long LL;
- const int MAXN = ;
- const int MAXM = ;
- const double eps = 1e-;
- const LL MOD = ;
- bool G[][];
- map<string, int>M;
- int cnt, w[], dp[], dp2[][], n, m;
- char str[], s[];
- int num[], tot;
- int get_index(char* s)
- {
- if(M[s]) return M[s];
- return M[s] = ++cnt;
- }
- void init()
- {
- int x, no;
- cnt = ; M.clear();tot = ;
- mem0(G); mem0(dp); mem0(num);
- sscanf(s, "%d %d", &n, &m);
- for(int i = ; i <= n; i ++) G[][i] = ;
- for(int i = ; i <= n; i ++)
- {
- gets(s);
- sscanf(s,"%s %d%*c", str, &x);
- if( !M[str] ) M[str] = ++cnt;
- w[no = M[str]] = x;
- int len = strlen(s), p = len - , index = ;
- while( !isdigit(s[p]) ) p --; p ++;
- if(p == len) continue;
- p++;
- while(p <= len)
- {
- if(p == len || s[p] == ' ')
- {
- str[index] = ;
- int id = get_index(str);
- G[no][id] = ;
- G[][id] = ;
- index = ;
- }
- else str[index++] = s[p];
- ++p;
- }
- }
- }
- void dfs1(int u)
- {
- dp[u] = INF;
- num[u] = ;
- for( int i = ; i <= n; i ++) if( G[u][i] )
- {
- dfs1(i);
- num[u] += num[i];
- }
- dp[] = ;
- }
- void dfs2(int u)
- {
- memcpy(dp2[u], dp, sizeof(dp));
- if(u) for(int i = tot; i >= ; i --)
- {
- dp2[u][i + num[u]] = min(dp[i + num[u]], dp[i] + w[u]);
- }
- for(int i = ; i <= n; i ++) if(G[u][i])
- dfs2(i);
- for(int i = ; i <= n; i ++)
- dp[i] = min(dp[i], dp2[u][i]);
- tot ++;
- }
- void print()
- {
- int ans = INF;
- for(int i = m; i <= n; i ++)
- ans = min(ans, dp[i]);
- printf("%d\n", ans);
- }
- int main()
- {
- // freopen("in.txt", "r", stdin);
- // freopen("out.txt", "w", stdout);
- while(gets(s) && s[] != '#')
- {
- init();
- dfs1();
- dfs2();
- print();
- }
- return ;
- }
POJ3345的更多相关文章
- poj3345 Bribing FIPA【树形DP】【背包】
Bribing FIPA Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 5910 Accepted: 1850 Desc ...
- POJ3345 Bribing FIPA 【背包类树形dp】
题目链接 POJ 题解 背包树形dp板题 就是读入有点无聊,浪费了很多青春 #include<iostream> #include<cstdio> #include<cm ...
- POJ3345 Bribing FIPA(树形DP)
题意:有n个国家,贿赂它们都需要一定的代价,一个国家被贿赂了从属这个国家的国家也相当于被贿赂了,问贿赂至少k个国家的最少代价. 这些国家的从属关系形成一个森林,加个超级根连接,就是一棵树了,考虑用DP ...
- POJ3345 Bribing FIPA
Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 5021 Accepted: 1574 Description There ...
- POJ1155 TELE(树形DP)
题目是说给一棵树,叶子结点有负权,边有正权,问最多能选多少个叶子结点,使从叶子到根的权值和小于等于0. 考虑数据规模表示出状态:dp[u][k]表示在u结点为根的子树中选择k个叶子结点的最小权值 最后 ...
- ACM学习大纲
1 推荐题库 •http://ace.delos.com/usaco/ 美国的OI 题库,如果是刚入门的新手,可以尝试先把它刷通,能够学到几乎全部的基础算法极其优化,全部的题解及标程还有题目翻译可以b ...
- poj 3345 Bribing FIPA (树形背包dp | 输入坑)
题目链接: poj-3345 hdu-2415 题意 有n个国家,你要获取m个国家的支持,获取第i个国家的支持就要给cost[i]的价钱 其中有一些国家是老大和小弟的关系,也就是说,如果你获 ...
- ACM训练大纲
1. 算法总结及推荐题目 1.1 C++ STL • STL容器: set, map, vector, priority_queue, queue, stack, deque, bitset• STL ...
- 树形DP小结
树形DP1.简介:树是一种数据结构,因为树具有良好的子结构,而恰好DP是从最优子问题更新而来,那么在树上做DP操作就是从树的根节点开始深搜(也就是记忆化搜索),保存每一步的最优结果.tips:树的遍历 ...
随机推荐
- 20160206.CCPP体系详解(0016天)
代码片段(01):.指针.c+02.间接赋值.c 内容概要:内存 ///01.指针 #include <stdio.h> #include <stdlib.h> //01.取地 ...
- Linux编程(获取系统时间)
#include <stdio.h> #include <time.h> int main() { time_t now; struct tm *w; time(&no ...
- js match regex
需要返回成数组元素的要放在括号里头 var arr = /input-([0-9]*)-([0-9]*)/.exec(id); var all = arr[0]; var row = arr[1]; ...
- ASIFormDataRequest 登录
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL: [NSURL URLWithString: @"http: ...
- ubuntu 查看系统版本信息
查看cpu信息cat /proc/cpiinfo 查看ubuntu版本:cat /etc/issue 查看系统是32位还是64位方法1:#查看long的位数,返回32或64 getconf LONG_ ...
- 将错误日志记录在txt文本里
引言 对于已经部署的系统一旦出错对于我们开发人员来说是比较痛苦的事情,因为我们不能跟踪到错误信息,不能 很快的定位到我们的错误位置在哪,这时候如果能像开发环境一样记录一些堆栈信息就可以了,这时候我们就 ...
- Android Ant批量打包
一.配置Ant环境变量 JAVA_HOME=/software/jdk1.6.0_24 ANT_HOME=/software/apache-ant-1.9.2 Android_Home=/softwa ...
- 对JAVA集合进行遍历删除时务必要用迭代器
java集合遍历删除的方法: 1.当然这种情况也是容易解决,实现方式就是讲遍历与移除操作分离,即在遍历的过程中,将需要移除的数据存放在另外一个集合当中,遍历结束之后,统一移除. 2.使用Iterato ...
- 【LR】安装LR11后遇到的问题
(1)问题:录制脚本时无法弹出IE浏览器 解决方法: 正确的是C:\Program Files (x86)\Internet Explorer\iexplore.exe 错误是:C:\Program ...
- list 容器 排序函数.xml
pre{ line-height:1; color:#f0caa6; background-color:#2d161d; font-size:16px;}.sysFunc{color:#e54ae9; ...