POJ3345 Bribing FIPA 树形DP

来源:互联网 发布:linux添加命令 编辑:程序博客网 时间:2024/04/29 16:40

Problem Address:http://poj.org/problem?id=3345


【前言】


前面的两篇都是把树转化为二叉树计算,虽然简单,但是不是很直观。

这份代码是直接用邻接表做。用vector记录邻接的边。

然后对每个结点直接进行背包。

相比起记忆化搜索,直接背包的好处就是少了很多次函数调用,应该是节省了不少时间。


【思路】


这道题比较难处理的是输入。

gets()读取整行数据。

sscanf用来从字符串读入。

stringstream可以用来设置输入流。

然后用map映射结点的索引号。

以0结点作为根节点,连接到每个原来的根。

先对子结点进行背包,再对父结点进行背包。

同时需要更新父结点。如果父结点在包含所有子结点时的费用小于当前费用,则需更新。


【代码】


#include <iostream>#include <map>#include <sstream>#include <vector>#include <string>using namespace std;const int maxn = 200;const int MAX = 99999999;map<string, int> ma;vector<int> adj[maxn+5];bool visited[maxn+5];int diamond[maxn+5];int dp[maxn+5][maxn+5];int n, m;int solve(int v){visited[v] = true;int i, j, k;int t, u;int num = 1;for (i=0; i<=n; i++)dp[v][i] = MAX;dp[v][0] = 0;for (i=0; i<adj[v].size(); i++){u = adj[v][i];if (visited[u]) continue;num += solve(u);for (j=n; j>0; j--){for (k=1; j-k>=0; k++){if (dp[v][j-k]+dp[u][k]<dp[v][j])dp[v][j] = dp[v][j-k] + dp[u][k];}}}if (dp[v][num]>diamond[v])dp[v][num] = diamond[v];return num;}int main(){char str[1000];char name[105];int index;int i, j, tn, tc;while(gets(str)){if (str[0]=='#') break;sscanf(str, "%d %d", &n, &m);index = 1;ma.clear();for (i=0; i<=n; i++){adj[i].clear();visited[i] = false;}for (i=0; i<n; i++){scanf("%s", name);if (ma.find(name)==ma.end()){ma[name] = index;index++;}tn = ma[name];scanf("%d", &diamond[tn]);gets(str);stringstream ss(str);while(ss>>name){if (ma.find(name)==ma.end()){ma[name] = index;index++;}tc = ma[name];adj[tn].push_back(tc);adj[tc].push_back(tn);if (!visited[tc])visited[tc] = true;}}diamond[0] = MAX;for (i=1; i<=n; i++){if (!visited[i])adj[0].push_back(i);}for (i=0; i<=n; i++)visited[i] = false;solve(0);int ans = MAX;for (i=m; i<=n; i++)if (dp[0][i]<ans)ans = dp[0][i];printf("%d\n", ans);}return 0;}


原创粉丝点击