??xml version="1.0" encoding="utf-8" standalone="yes"?>
]]>
]]>
]]>
先来看一个比较有挑战性的题目Q)
Problem
Bob喜欢玩电脑游戏,特别是战略游戏。但是他l常无法扑ֈ快速玩q游戏的办法。现在他有个问题?
他要建立一个古城堡Q城堡中的\形成一|。他要在q棵树的l点上放|最数目的士兵Q得这些士兵能了望到所有的路?
注意Q某个士兵在一个结点上Ӟ与该l点相连的所有边都可以被了望到?
请你~一E序Q给定一树,帮Bob计算Z需要放|最的士兵.
Input
W一行ؓ一整数Q,表示有l测试数?
每组试数据表示一|Q描q如下:
W一?NQ表C树中结点的数目?
W二行至WN+1行,每行描述每个l点信息Q依ơؓQ该l点标号iQk(后面有k条边与结点I相连)?
接下来k个数Q分别是每条边的另一个结Ҏ号r1Qr2Q?..Qrk?
对于一个n(0<n<=1500)个结点的树,l点标号?到n-1之间Q在输入数据中每条边只出Cơ?/font>
Output
输出文g仅包含一个数Qؓ所求的最的士兵数目?/font>
Q-Q-Q-Q-Q-Q-Q-Q-Q?wbr>Q-Q-Q-Q-Q-Q-Q?
q个题目?4q高二准备NOIP的时候看到过Q当时打L有想出有效的解决Ҏ。然后就拿着题目去问我们廖老师Q廖老师一拿到题目题目q没看完Q立马给Z解决ҎQ不会考这么难的题。于是这个题目也遗留了下来Q没惛_事隔q么多年以后又重新见识了q个题目Q倍感亲切Q呵呵~?
q个题目看上L图论Q贪心是明显错误的。用动态规划的思想可以很有效地解决。就看你能不能看出来是动态规划。就像杨潇说的:动态规划这c题Q别Z说就明白Q自己就很难惛_?
在给个题目的状态{ULE之前,我们先从更简单的树型动态规划入手,看看其他一些题目?
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
题目
有一苹果树Q如果树枝有分叉Q一定是?叉(是说没有只?个儿子的l点Q?
q棵树共有N个结点(叶子Ҏ者树枝分叉点Q,~号?-N,树根~号一定是1?
我们用一Ҏ枝两端连接的l点的编h描述一Ҏ枝的位置。下面是一颗有4个树枝的?
2 5
\ /
3 4
\ /
1
现在q颗树枝条太多了Q需要剪枝。但是一些树枝上长有Ҏ?
l定需要保留的树枝数量Q求出最多能留住多少Ҏ?/font>
输入格式
W??个数QN和Q(1<=Q<= N,1<N<=100)?
N表示树的l点敎ͼQ表示要保留的树枝数量。接下来N-1行描q树枝的信息?
每行3个整敎ͼ前两个是它连接的l点的编受第3个数是这Ҏ枝上Ҏ的数量?
每根树枝上的Ҏ不超q?0000个?/font>
输出格式
一个数Q最多能留住的苹果的数量?
Q-Q-Q-Q-Q-Q-Q-Q-Q?wbr>Q-Q-Q-Q-Q-Q-Q?
我们用a[i][j]描述树,f[i][m]表示Wi个节点下Q共保留m个树枝的最大苹果数目?
[问题描述]
在大学里每个学生Qؓ了达C定的学分Q必M很多评里选择一些课E来学习Q在评里有些课E必d某些评之前学习Q如高等数学L在其它课E之前学习。现在有N门功课,每门课有个学分,每门课有一门或没有直接先修课(若课Ea是课Eb的先修课卛_有学完了评aQ才能学习课EbQ。一个学生要从这些课E里选择M门课E学习,问他能获得的最大学分是多少Q?/font>
输入Q?
W一行有两个整数N,M用空格隔开?1<=N<=200,1<=M<=150)
接下来的N?WI+1行包含两个整数ki和si, ki表示WI门课的直接先修课Qsi表示WI门课的学分。若ki=0表示没有直接先修课(1<=ki<=N, 1<=si<=20Q?/font>
输出Q?
只有一行,选M门课E的最大得分?/font>
Q-Q-Q-Q-Q-Q-Q-Q-Q?wbr>Q-Q-Q-Q-Q-Q-Q?
0 0
/ | \ ----> /
1 2 3 1Q?Q?
辈䆾虽然变了Q但是还是有办法处理的?
f[i][k]=max{ s[i]+f[i.L][j]+f[i.R][k-j-1] , f[i.R][k] }
其中后边那个f[i.R][k]是处理转换Z叉树时的关系的?
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
看到q里Q树型动态规划应该可以有个初步了解了Q那么我们回到最初的那个题目“战略游戏”?
f[v][0]={ ∑f[v.Son][1] }
f[v][1]={ ∑min{ f[v.Son][0], f[v.Son][1] }+1 }
q样问题便完解决了,旉复杂度O(n2)
下面再来一个题目作为思\扩展,和刚刚的题目cM:
背景
有个公司要D行一场晚会?
Z能玩得开心,公司领导军_Q如果邀请了某个人,那么一定不会邀请他的上?
Q上司的上司Q上司的上司的上?#8230;…都可以邀P?/font>
题目
每个参加晚会的h都能为晚会增M些气氛,求一个邀h案,使气氛值的和最大?/font>
输入格式
W?行一个整数NQ?<=N<=6000Q表C公司的人数?
接下来N行每行一个整数。第i行的数表C第i个h的气氛值x(-128<=x<=127)?
接下来每行两个整数LQK。表C第K个h是第L个h的上司?
输入? 0l束?/font>
输出格式
一个数Q最大的气氛值和?/font>
]]>
Total Submission(s): 1391 Accepted Submission(s): 577
Each test case contains a single line with several words. There will be at most 1000 characters in a line.
3
olleh !dlrow
m'I morf .udh
I ekil .mca
hello world!
I'm from hdu.
I like acm.
#include <string.h>
int main()
{
int i=0,n,length,t,j;
char ch,p[1001],temp;
scanf("%d",&n);
ch=getchar();
while(n--)
{
gets(p);
length=strlen(p);
t=0;
for(i=0;i<=length;i++)
{
if(p[i]==' '||p[i]=='\0')
{
for(j=t;j<(i+t)/2;j++)
{
temp=p[j];
p[j]=p[i-j+t-1];
p[i-j+t-1]=temp;
}
t=i+1;
}
}
printf("%s\n",p);
}
return 0;
}
]]>
#include <string.h>
#include <ctype.h>
char * index( const char *s, int c);
/*
** State machine for romantoint
**
** M D C L X V I
** 0: +1000/0 +500/0 +100/1 +50/0 +10/2 +5/0 +1/3
** 1: +800/0 -- +100/0 +50/0 +10/2 +5/0 +1/3
** 2: -- -- +80/0 +30/0 +10/2 +5/0 +1/3
** 3: -- -- -- -- +8/0 +3/0 +1/3
**
*/
int FromRoman(char *s)
{
int n=0;
int prev=0;
while (*s!=' '&&*s!=NULL) {
switch (toupper(*s))
{
case 'M': n += 1000 - prev*2;
prev=0;
break;
case 'D': n += 500 - prev*2;
prev=0;
break;
case 'C': n += 100;
if (prev < 100) n -= 2*prev;
prev=100;
break;
case 'L': n += 50;
if (prev < 50) n -= 2*prev;
prev=0;
break;
case 'X': n += 10;
if (prev < 10) n -= 2*prev;
prev=10;
break;
case 'V': n += 5;
if (prev < 5) n -= 2*prev;
prev=0;
break;
case 'I': n += 1;
prev=1;
break;
}
s++;
}
return n;
}
void PrintRoman(int n)
{
if (n<=0 || n>4999)
{
printf("out of range exception\n");
return;
}
while (n/1000)
{
printf("M");
n -= 1000;
}
switch(n/100)
{
case 0: break;
case 1: printf("C"); break;
case 2: printf("CC"); break;
case 3: printf("CCC"); break;
case 4: printf("CD"); break;
case 5: printf("D"); break;
case 6: printf("DC"); break;
case 7: printf("DCC"); break;
case 8: printf("DCCC"); break;
case 9: printf("CM"); break;
}
n %= 100;
switch(n/10)
{
case 0: break;
case 1: printf("X"); break;
case 2: printf("XX"); break;
case 3: printf("XXX"); break;
case 4: printf("XL"); break;
case 5: printf("L"); break;
case 6: printf("LX"); break;
case 7: printf("LXX"); break;
case 8: printf("LXXX"); break;
case 9: printf("XC"); break;
}
n %= 10;
switch(n) {
case 0: break;
case 1: printf("I"); break;
case 2: printf("II"); break;
case 3: printf("III"); break;
case 4: printf("IV"); break;
case 5: printf("V"); break;
case 6: printf("VI"); break;
case 7: printf("VII"); break;
case 8: printf("VIII"); break;
case 9: printf("IX"); break;
}
printf("\n");
}
#define STACKSIZE 1024
int nitems=0;
int stack[STACKSIZE];
int Pop()
{
if (!nitems) {
printf("stack underflow\n");
return 0;
}
return stack[--nitems];
}
void Push(int n)
{
if (nitems == STACKSIZE-1) {
printf("stack overflow\n");
return;
}
stack[nitems++] = n;
}
int PrintTop(void)
{
if (!nitems) {
printf("stack underflow\n");
return -1;
}
else {
PrintRoman(stack[nitems-1]);
return 0;
}
}
int PerformAdd(void)
{
int x,y;
if (nitems < 2) {
printf("stack underflow\n");
return -1;
}
y = Pop();
x = Pop();
Push(x+y);
return 0;
}
int PerformSub(void)
{
int x,y;
if (nitems < 2) {
printf("stack underflow\n");
return -1;
}
y = Pop();
x = Pop();
Push(x-y);
return 0;
}
int PerformMul(void)
{
int x,y;
if (nitems < 2) {
printf("stack underflow\n");
return -1;
}
y = Pop();
x = Pop();
Push(x*y);
return 0;
}
int PerformDiv(void)
{
int x,y;
if (nitems < 2) {
printf("stack underflow\n");
return -1;
}
y = Pop();
x = Pop();
if (y!=0)
Push(x/y);
else {
printf("division by zero exception\n");
Push(x);
}
return 0;
}
main()
{
char line[256];
//freopen("H.in","r",stdin);
// freopen("H.out","w",stdout);
while (fgets(line,sizeof(line),stdin)) {
if (line[0] == '=')
PrintTop();
else if (line[0] == '+')
PerformAdd();
else if (line[0] == '-')
PerformSub();
else if (line[0] == '*')
PerformMul();
else if (line[0] == '/')
PerformDiv();
else {
int n = FromRoman(line);
if (n > 0) {
Push(n);
}
}
}
}