把二维按行列分解然后dp。
dp[i][0]表示不取第i个能到的最大值
所以dp[i][0] = Max(dp[i-1][0],dp[i-1][1]);
dp[i][1]表示取第i个能到的最大值
_所以dp[i][1] = _dp[i-1][0]+value[i];__
row[i]记录下每一行的最优情况,然后再按照上面的方法进行dp
1 |
|
把二维按行列分解然后dp。
dp[i][0]表示不取第i个能到的最大值
所以dp[i][0] = Max(dp[i-1][0],dp[i-1][1]);
dp[i][1]表示取第i个能到的最大值
_所以dp[i][1] = _dp[i-1][0]+value[i];__
row[i]记录下每一行的最优情况,然后再按照上面的方法进行dp
1 | #include <stdio.h> |
多重背包问题,用n个物品,每个物品有价值v[i],每个物品数量限制为num[i]。
这道题是问,用所有的硬币能够在m的范围内最多可以组合成多少种价值。
1 | 对于每个硬币而言: |
_(对于num,类似于编码。当2^n _<=num/2时:k = 2^n(n=0,1,2,……)表示状态,对应下来就是二进制的某一位数是1,然后还有一个状态就是k>num/2的时候啦,num+1-k,这样下来就可以用k来组合枚举出从1->num的所有可能了。然后对于k,单位价值和大小都乘上k之后就变成了一个0-1背包)
1 | #include <stdio.h> |
题目大意:在一条直线型的铁路上,每个站点有各自的权重num[i],每一段铁路(边)的权重(题目上说是战略价值什么的好像)是能经过这条边的所有站点的乘积之和.。然后给你m个炮弹,让你选择破坏掉m段铁路,使剩下的整条铁路的战略价值最小。
四边形优化的动态规划,做题时看了别人的解题报告后还不怎么明白四边形优化咋一回事,于是只能贴代码了~
1 | #include <stdio.h> |
本题直接用宽搜解决,我是沙茶。如题所述,标记为X的地方可以直接通过(不增加步数),标记为’. ’的地方步数要加1。直接宽搜的话会超时~ 于是就用两个BFS,两个队列。先调用第一个BFS,如果进入标记是X的地方,则调用第二个BFS2直接先遍历完其他所有相邻的标记为X的区域。
1 | #include<stdio.h> |
挺不错的一道题目,并查集的确是最优美的数据结构之一。
题目大意:有N个piles(按序编号),每次有两种操作:
M x y 表示把x所在的那一堆全部移到y所在的那一堆
C x 询问在x之下有多少个方块
解决方法:使用并查集(路径压缩)实现,然后用count[X]表示X所在的那一堆总共多少个piles,under[x]表示x之下有多少个piles。
首先,每次操作我们合并两个集合(如果原来在同一集合中除外),count[X]是每次操作可以直接实现的,就是把两堆的数目相加,很容易(初始值为1)。那么当某次移动操作发生时,首先确定x所在的那一堆最底部的X以及y所在那一堆最底部的Y,那么under[X]的数目就是另外一堆piles的总数count[Y],有了这个条件,在接下去的操作中,就可以根据FIND(x)递归去一边寻找根一边更新其他未知的under[x]。
1 | #include <stdio.h> |
很水的一道题,数论做的很少。这题的输入是一个数列中的前三个数,然后根据输入判断是等差数列还是等比数列,然后求出第n项。囧,高中的公式就不写了~~
需要注意的地方是对结果取摸:A×B%M = ((A%M)*((B%M)%M)
最重要是求等比数列的时候: 求幂乘要用二分来乘,否则会TLE
1 | #include <stdio.h> |
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4003
大连网络赛的题目(比赛时候几乎就是瞄了一眼而已~囧),然后前两天一直想A掉这题,结果感冒发烧了T_T一直放着,最后也还是看了大牛的题解才写出代码,树形DP还是不行啊~~
这题是树DP,最关键的地方还是对于每个顶点的状态转移,要注意两个地方,一个是DFS控制方向往深处搜索下去(这也是DFS的奥妙),第二点就是类似背包的顶点转移方程。
1 | 首先考虑平凡的: |
然后对每条边进行转移dp[u][j] = MIN(dp[u][j],dp[u][j-k]+dp[Child][k]+ k个机器人路过这条边的总代价)
晒一下我的代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Maxn 10001
typedef struct Node
{
int NO_;
int Cost;
struct Node* NextChild;
}Node;
Node* FirstChild[Maxn];
enum boolean{FALSE,TRUE};
int dp[Maxn][12];
int N,S,K;
void DFS(int u,int From)
{
int i,j,k;
int Child;
Node *p;
for (p = FirstChild[u]; p!=NULL; p=p->NextChild)
{
Child = p->NO_;
if (Child!=From)
DFS(Child,u);
}
for (p = FirstChild[u];p!=NULL;p=p->NextChild)
{
Child = p->NO_;
if (Child!=From)
{
for (j = K; j>= 0; j--)
{
dp[u][j] += dp[Child][0]+2*(p->Cost);
for (k = 0; k <= j; k++)
if (dp[u][j-k]+dp[Child][k]+k*(p->Cost)<dp[u][j])
dp[u][j] = dp[u][j-k]+dp[Child][k]+k*(p->Cost);
}
}
}
}
int main()
{
freopen("Sample Input.txt","r",stdin);
int i,j,k;
int u,v,w;
Node *p;
while(scanf("%d%d%d",&N,&S,&K)!=EOF)
{
memset(FirstChild,0,sizeof(FirstChild));
for (i = 1; i <= N-1; i++)
{
scanf("%d%d%d",&u,&v,&w);
p = (Node*)malloc(sizeof(Node));
p->Cost = w;
p->NO_ = v;
p->NextChild = FirstChild[u];
FirstChild[u] = p;
p = (Node*)malloc(sizeof(Node));
p->Cost = w;
p->NO_ = u;
p->NextChild = FirstChild[v];
FirstChild[v] = p;
}
memset(dp,0,sizeof(dp));
DFS(S,-1);
printf("%d\n",dp[S][K]);
}
getch();
return 0;
}
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586
题目是说:N个顶点形成树,接下来有M次询问两个顶点间的距离~
解题思路:用Tarjan脱机最小公共祖先算法(
P319)
然后计算两个顶点到根部的距离加起来与他们公共祖先到根部的距离乘以2的绝对值
Dist(u,v) = abs(dist[u]+dist[v]-2*dist[ancestor[v]]);
Tarjan算法我是看着
(我觉得里面好像还很多问题)
晒一下我的代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define Maxn 40001
typedef struct Node
{
int NO_;
int D;
struct Node *NextChild;
}Node;
Node* FirstChild[Maxn];
int ancestor[Maxn];
int p[Maxn];
int rank[Maxn];
int dist[Maxn];
enum boolean{FALSE,TRUE};
enum COLOR{WHITE,BLACK};
unsigned char color[Maxn];
unsigned char Visit[Maxn];
void MAKE_SET(int x)
{
p[x] = x;
rank[x] = 0;
}
void LINK(int x,int y)
{
if (rank[x]>rank[y])
p[y] = x;
else
{
p[x] = y;
if (rank[x]==rank[y])
rank[y]++;
}
}
void UNION(int x,int y)
{
LINK(FIND_SET(x),FIND_SET(y));
}
int FIND_SET(x)
{
if ( x!=p[x] )
p[x] = FIND_SET(p[x]);
return p[x];
}
void LCA(int u)
{
if (Visit[u])
return;
Visit[u] = TRUE;
int v;
MAKE_SET(u);
ancestor[FIND_SET(u)] = u;
Node *p;
for (p = FirstChild[u]; p; p=p->NextChild)
{
v = p->NO_;
dist[v] = dist[u] + p->D;
LCA(v);
UNION(u,v);
ancestor[FIND_SET(u)] = u;
}
color[u] = BLACK;
}
int main()
{
freopen("Sample Input.txt","r",stdin);
int T;
int n,m;
int i,j,k;
int u,v,w;
Node *p;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
memset(FirstChild,NULL,sizeof(FirstChild));
memset(Visit,FALSE,sizeof(Visit));
memset(dist,0,sizeof(dist));
for (i = 1; i <= n-1; i++)
{
scanf("%d%d%d",&u,&v,&w);
p = (Node*)malloc(sizeof(Node));
p->NO_ = v;
p->D = w;
p->NextChild = FirstChild[u];
FirstChild[u] = p;
p = (Node*)malloc(sizeof(Node));
p->NO_ = u;
p->D = w;
p->NextChild = FirstChild[v];
FirstChild[v] = p;
}
LCA(1);
for (i = 1; i <= m; i++)
{
scanf("%d%d",&u,&v);
printf("%d\n",abs(dist[u]+dist[v]-2*dist[ancestor[v]]));
}
}
getch();
return 0;
}
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520
最基本的树形DP,题目描述了一个学校的员工的分布按树的结构。每个员工对应一个快乐指数,在树中选取员工(约束条件:每个员工和他的直属上司不能同时选取,就是孩子结点和父亲结点不能够共存),然后使选取的员工的快乐指数之和达到最大值。
用dp[i][0]表示选取第i个员工,不包括员工自己时的最大快乐指数和。
dp[i][1]表示选取第i个员工,包括员工自己时的最大快乐指数和。
对于每个结点:
dp[i][0] = 所有孩子结点的最大快乐指数和
dp[i][1] = 自己的快乐指数+所有孩子不包括孩子自身时的最大快乐指数之和
1 | #include <stdio.h> |
题目链接:http://acm.hdu.edu.cn/status.php?user=XHC91&pid=1011&status=5
这题是一道树形DP,从1号顶点进入树中,每次可以分配小兵到其他可达的顶点去,杀死所有的bugs可以获取brain值,求出m个小兵最多能获取多少brain值。这题要对顶点进行DFS一搜到底,然后用背包的方法选取孩子节点中最多的brain。
对于一个父母顶点,除去它的brain和cost之后,剩下的问题就是一个大小为m-cost的背包了,再由它的孩子节点中任意选取顶点顶点,最终必获得父母顶点的最大值。
1 | #include <stdio.h> |