威尼斯人官网玛利亚为能够如期且安全的达最终一个站以及对方见面。内存限制。

【SinGuLaRiTy-1026】
Copyright (c) SinGuLaRiTy 2017. All Rights Reserved.

题材链接:http://noi.openjudge.cn/ch0207/7219/

[UVA 1025] A Spy in the Metro

总时间范围: 
200ms

题材叙述

特务玛利亚让送及S市执行一个特别危险的任务。她索要采用地铁好他的任务,S市的地铁仅出雷同漫漫路线运行,所以并无复杂。

玛利亚发生一个任务,现在的时呢0,她一旦由第一个站起身,并于最后一立的特工碰头。玛利亚清楚出一个有力的集团在追踪其,她知晓如果直接呆在一个车站,她会客起十分可怜之于逮的高风险,躲在运作的列车中凡较安全之。所以,她决定尽可能地呆在运作的列车中,她只得向前面或为后以车。

玛利亚以能够准时且安全之抵最终一个车站和对方会,需要掌握在在车站最为小等时总和的计划。你要写一个序,得到玛丽亚最短的待时。当然,到了终点站之后如果时间还没有交规定的天天,她好以站里等正在对方,只不过是等待的时刻呢是一旦算进去的。

斯城市发生n个站,编号是1-n,火车是如此走的:从第一单车站开始至最后一个站。或者从最后一立发车然后开会来。火车在列特定个别站中行驶的年华是稳的,我们为可忽略停车的年月,玛利亚之速度极其快,所以他得以很快达到上任就少部车而到站。

内存限制: 
65536kB

输入

输入文件包含多组数据,每组数据还是因为7行组成
第1实施:一个正整数N(2<=N<=50)表示站的数量
第2执:一个正整数T(0<=T<=200)表示用之会时
第3推行:1-(n-1)个刚刚整数(0<ti<70)表示两立间列车的经时间
第4履:一个平头M1(1<=M1<=50)表示去第一只站的火车的数据
第5执行:M1只正整数:d1,d2……dn,(0<=d<=250都di<di+1)表示每一样排列列车离第一立的辰
第6实行:一个刚整数M2(1<=M2<=50)表示去第N站的火车的数码
第7实践:M2只刚刚整数:e1,e2……eM2,(0<=e<=250都ei<ei+1)表示每一样排列列车离第N站的年月
末一推行有一个整数0。

输出

于每个测试案例,打印一实践“Case
Number N:
”(N从1开始)和一个平头表示总待的不过缺少日还是一个单词“impossible”如果玛丽亚不容许得。按照样例的出口格式。

描述
将刚刚整数n 表示成一多重正整数的同,n=n1+n2+…+nk, 其中n1>=n2>=…>=nk>=1 ,k>=1 。
恰巧整数n 的这种代表称正整数n 的细分。

样例数据

样例输入 样例输出

4
55
5 10 15
4
0 5 10 20
4
0 5 10 15
4
18
1 2 3
5
0 3 6 10 12
6
0 3 5 7 12 15
2
30
20
1
20
7
1 3 5 7 11 13 17
0

Case Number 1: 5
Case Number 2: 0
Case Number 3: impossible

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

输入
专业的输入包含若干组测试数据。每组测试数据是单排输入数据,包括个别只整数N
和 K。 
(0 < N <= 50, 0 < K <= N)

解析

一道DP题目,dp[i][j]代表至第i单市之时节
,时间吗j的等候时最少是有些,然后换方程即可。

输出
对每组测试数据,输出以下三行数据:
先是尽: N划分成K个正整数的与之分割数目
亚推行: N划分成多少单不等正整数的与底撤并数目
其三实践: N划分成多少单奇正整数的与的分割数目

Code

#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<iostream>

#define MAXN 110

using namespace std;
int a[MAXN];
int d1[MAXN][MAXN],d2[MAXN][MAXN];
int m1,m2;
int dp[MAXN][400];

int main()
{
    int n;
    int T=1;
    while(scanf("%d",&n)&&n!=0)
    {
        int t;
        scanf("%d",&t);
        for(int i=1;i<=n-1;i++)
            scanf("%d",&a[i]);

        scanf("%d",&m1);
        for(int i=1;i<=m1;i++)
            scanf("%d",&d1[1][i]);
        sort(d1[1]+1,d1[1]+m1+1);

        scanf("%d",&m2);
        for(int i=1;i<=m2;i++)
            scanf("%d",&d2[n][i]);
        sort(d2[n]+1,d2[n]+m2+1);

        dp[0][1]=0;
        for(int i=1;i<=m1;i++)
            for(int j=1;j<=n-1;j++)
                d1[j+1][i]=d1[j][i]+a[j];

        for(int i=1;i<=m2;i++)
            for(int j=n-1;j>=1;j--)
                d2[j][i]=d2[j+1][i]+a[j];

        for(int i=0;i<=t;i++)
            for(int j=1;j<=n;j++)
                dp[j][i]=t+1;

        dp[1][0]=0;
        for(int j=0;j<=t;j++)
            for(int i=1;i<=n;i++)
                if(dp[i][j]<=t)
                {
                    int k;
                    for(k=1;k<=m1;k++)
                        if(d1[i][k]>=j)
                            break;
                    if(d1[i][k]-j+dp[i][j]<dp[i+1][j+a[i]+d1[i][k]-j]&&k<=m1)
                        dp[i+1][j+a[i]+d1[i][k]-j]=d1[i][k]-j+dp[i][j];
                    for(k=1;k<=m2;k++)
                        if(d2[i][k]>=j)
                            break;
                    if(k<=m2&&d2[i][k]-j+dp[i][j]<dp[i-1][j+a[i-1]+d2[i][k]-j])
                        dp[i-1][j+a[i-1]+d2[i][k]-j]=d2[i][k]-j+dp[i][j];
                }

        for(int i=1;i<=t;i++)
            if(dp[n][i]<t)
                dp[n][t]=min(dp[n][i]+t-i,dp[n][t]);

        if(dp[n][t]<=t)
            printf("Case Number %d: %d\n",T++,dp[n][t]);
        else
            printf("Case Number %d: impossible\n",T++);
    }
    return 0;
}

样例输入
5 2

[UVA 437] The Tower of Babylon

样例输出
2
3
3

问题叙述

或许你已听了巴比伦塔的传说,现在以此故事之群细节就给遗忘了。现在,我们只要告知你一切故事:
巴比伦人有n种不同的积木,每种积木都是拳拳长方体,且数额还是绝的。第i种植积木的增长宽高分别吗{xi,yi,zi}。积木可以于盘,所以前面的丰富宽高是得换的。也就算是中间2单结合底部的长方形,剩下的一个乎高度。巴比伦人想只要的所以积木来尽可能地打还强的塔,但是片块积木要叠在一道是发原则的:只有积木A的最底层2独限都小于积木B的平底相对的2单限经常,这积木A才得以折叠在积木B上方。例如:底部也3×8的积木可以置身脚也4×10底积木上,但是无法在脚也6×7之积木上。
为您有些积木的数目,你的任务是描摹一个程式算有可以堆出之宝塔高是稍微。

出口说明
第一行: 4+1, 3+2,
第二行: 5,4+1,3+2
第三行: 5,1+1+3, 1+1+1+1+1+1

输入

输入数据会含有多组数据。
于列一样组数被:第1执包含一个整数n,表示来n
(1<=n<=30)种不同的积木。接下来的n行,每行给闹3独整数,表示同样块积木的丰富宽高。
当n=0时,输入数据截止。

分析

参照来源:http://blog.csdn.net/tp7309/article/details/54880495

平头划分问题立马几只变形确实挺经典,需要一个个征下: 
设dp[n][m]表示数n划分方案被,每个数 不大于m 的划分数。

输出

对此各一样组数,按照以下格式输出答案:
Case case:
maximum height = height

N划分成多独可同等正整数的同(递归分析与实现)

分割分点儿种状态:

  • 分中每个数还小于m:则分数也dp[n][m-1]。
  • 分割中至少发生一个数等于m:则由n中减去去m,然后于n-m中还劈,则分数也dp[n-m][m]。

动态转换方程:dp[n][m]=dp[n][m-1]+dp[n-m][m]。

样例数据

样例输入 样例输出

1
10 20 30
2
6 8 10
5 5 5
7
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7
5
31 41 59
26 53 58
97 93 23
84 62 64
33 83 27
0

Case 1: maximum height = 40
Case 2: maximum height = 21
Case 3: maximum height = 28
Case 4: maximum height = 342

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

N划分成多个例外正整数的同

划分分点儿种状况:

  • 分中每个数都小于m:则分数为dp[n][m-1]。
  • 分割中最少有一个数等于m:则从n中减去m,然后从n-m中再细分,且再次细分的高频惨遭每个数如小于m,
    则划分数也dp[n-m][m-1]。

动态转换方程:dp[n][m]=dp[n][m-1]+dp[n-m][m-1]。

解析

新一押,有接触像极丰富及升子序列类型的题材。对于积木可以转这一个尺度,我们可拿不同状态(总共发生6种,自己画图吧)下的积木看成不同品类之积木。为了有利于以后DP的论断,我们于DP之前先小地预处理以下:对每一样栽积木,按照底面积增加排序。后面的DP过程比较好怀念,大家可看代码。

N划分成K个正整数的与(递归分析及落实)

设dp[n][k]表示数n划分成k个正整数的与时之划分数。 
分分点儿种情景:

  • 划分中未带有1:则要求每个数都大于1,可以优先以出k个1分至各个一样卖,之后以n-k中重新分叉k份,即dp[n-k][k]。
  • 细分中涵盖1:则打n中减去1,然后由n-1中又分k-1卖,
    则划分数也dp[n-1][k-1]。

动态转换方程:dp[n][k]=dp[n-k][k]+dp[n-1][k-1]。

Code

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>

#define MAXN 30*6+10

using namespace std;

struct Block
{
    int x,y,h;
    void fun(int a,int b,int c)
    {
        x=a;
        y=b;
        h=c;
    }
}node[MAXN];

bool cmp(Block r,Block t)
{
        return r.x*r.y<t.x*t.y;
}

int dp[MAXN];

int main()
{
    int num,cnt=0;
    while(scanf("%d",&num)!=EOF)
    {
        if(!num)
            return 0;
        int a,b,c;
        int m=0;
        for(int i=0;i<num;i++)
        {
            cin>>a>>b>>c;
            node[m++].fun(a, b, c);
            node[m++].fun(a, c, b);
            node[m++].fun(b, a, c);
            node[m++].fun(b, c, a);
            node[m++].fun(c, a, b);
            node[m++].fun(c, b, a);
        }
        sort(node,node+m,cmp);
        int maxlen=0;
        memset(dp,0,sizeof(dp));
        for(int i=0;i<m;i++)
        {
            dp[i]=node[i].h;
            for(int j=0;j<i;j++)
                if(node[i].x>node[j].x&&node[i].y>node[j].y)
                    dp[i]=max(dp[i],dp[j]+node[i].h);
            if(dp[i]>maxlen)
                maxlen=dp[i];
        }
        cout<<"Case "<<++cnt<<": maximum height = "<<maxlen<<endl;
    }
    return 0;
}

N划分成多个奇正整数的同

设f[i][j]代表用数i分成j个正奇数,g[i][j]表示以数i分成j个刚偶数。 
第一要先让j个分叉每个分单1,因为奇数加1即为偶数,所以只是得: 
f[i-j][j] = g[i][j]。 
划分分点儿栽状况:

  • 分开中未包含1:则要求每个数都大于1,可以先行以出k个1分及各国一样客,刚可拿问题易为”从i-j中分j个偶数”,即g[i-j][j]。
  • 分中涵盖1:则于n中减去1,然后从n-1中再度劈k-1份,
    则划分数为f[n-1][k-1]。

动态转换方程:f[i][j]=f[i-1][j-1]+g[i-j][j]。

 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4 #define N 51
 5 int dp1[N][N];    //N划分成K个正整数之和的划分数目。
 6 int dp2[N][N];    //N划分成若干个不同正整数之和的划分数目。
 7 int dp3[N][N];    //N划分成若干个可相同的正整数之和的划分数目。
 8 int f[N][N];      //N划分成K个奇正整数之和的划分数目。
 9 int g[N][N];      //N划分成K个偶正整数之和的划分数目。
10 
11 void initDivideInt() {
12     memset(dp1, 0, sizeof(dp1));  //dp[n][k]=dp[n-k][k]+dp[n-1][k-1]
13     memset(dp2, 0, sizeof(dp2));  //dp[n][m]=dp[n][m-1]+dp[n-m][m-1]
14     memset(dp3, 0, sizeof(dp3));  //dp[n][m]=dp[n][m-1]+dp[n-m][m]
15 
16     for (int i = 1; i < N; i++) {
17         for (int j = 1; j < N; j++) {
18             if (i < j) {
19                 dp1[i][j] = 0;
20                 dp2[i][j] = dp2[i][i];
21                 dp3[i][j] = dp3[i][i];
22             }
23             else if (i == j) {
24                 dp1[i][j] = 1;
25                 dp2[i][j] = dp2[i][j - 1] + 1;
26                 dp3[i][j] = dp3[i][j - 1] + 1;
27             }
28             else {
29                 dp1[i][j] = dp1[i - j][j] + dp1[i - 1][j - 1];
30                 dp2[i][j] = dp2[i][j - 1] + dp2[i - j][j - 1];
31                 dp3[i][j] = dp3[i][j - 1] + dp3[i - j][j];
32             }
33         }
34     }
35 }
36 
37 //f[i][j]=f[i-1][j-1]+g[i-j][j]
38 void initDivideOdd() {
39     f[0][0] = 1;
40     g[0][0] = 1;
41     for (int i = 1; i < N; i++) {
42         for (int j = 1; j <= i; j++) {
43             g[i][j] = f[i - j][j];
44             f[i][j] = f[i - 1][j - 1] + g[i - j][j];
45         }
46     }
47 }
48 
49 int main() {
50 //  freopen("in.txt", "r", stdin);
51     int n, k;
52     initDivideInt();
53     initDivideOdd();
54     while (cin >> n >> k) {
55         cout << dp1[n][k] << endl;
56         cout << dp2[n][n] << endl;
57 
58         int sum = 0;
59         for (int i = 0; i <= n; i++) {
60             sum += f[n][i];
61         }
62         cout << sum << endl;
63     }
64     return 0;
65 }

 

旁一样篇分析:http://www.cnblogs.com/sjymj/p/5385436.html

推介阅读:http://blog.csdn.net/codingdd/article/details/61414550

 

[UVA 1347 | POJ 2677] Tour

题材叙述

John
Doe是一律称佳绩之飞行员。一涂鸦,他操租一绑架有点飞机开始旅行有美观之地方。John
Doe为祥和统筹之飞路线满足以下要求:
1>路线经过所有的城;2>路线由太左边的地方开始,先严格为右侧,到达最右边的地方后,再严厉为左回到出发的地方;3>两单地点之间的门路是直线。
今昔,给闹各一个点的坐标,请你请出满足要求的不过短路线的长短。

同等词话题意:有n个点,给出x、y坐标。找来一致长条总长,从极度左边的触及出发,严格为右侧走至最右面点还严厉为左回到最左点。问尽差路径的长度是聊?

输入

输入文件包含多组数。

各个一样组数据的第1实施包含一个平头n
(1<=n<=1000),表示点的数。接下来的n行,每行包含两独浮点数(double)
xi,yi,表示一个触及的坐标为(xi,yi)。

输出

于各级一样组测试数据,输出一个鲜号小数,表示若算出底不过短距离。

样例数据

样例输入 样例输出

3
1 1
2 3
3 1
4
1 1
2 3
3 1
4 2

6.47
7.89

 

 

 

 

 

 

 

 

解析

<题目类型:双调欧几里得旅行商问题>

1.先是需以本来问题转化为,两只人A、B同时于极度左边的触发出发,一起严格为最好右点走,且经所有点一糟(除了最左点和极致右侧点)。这半单问题有等价性。
2.先自然想到用dp(i,j)表示A走及i,B走及j时的状态还用走多远到终点(注意表示的是还有多少届巅峰,所以该结果和眼前怎么动的无关),那么得印证dp(i,j)==dp(j,i);这里有人或会见疑惑为什么会当,刚刚说罢dp(i,j)表示已经达到这状态后尚需要活动多远到顶峰,与怎么到这个状态的并无提到,所以dp(i,j)和dp(j,i)只是片只人口角色对换了罢了。
3.想到就同一步后,会产出一个题材,就是dp(i,j)无法知道i、j之间的某些点是否已经走过了,所以我们要进一步考虑,刚刚我们提到,dp(i,j)==dp(j,i),那么我们就可以尽为i>=j(等于只有极端与起点上)。如果j>i了,只待交换A、B的角色即可,即将i换为j,j换为i。
4.出矣这个规格以后,我们就算得规定dp(i,j)规定吗:A在i,B在j(i>=j)且i之前的所有点都走过了,这样呢非见面漏解,为什么也?我们的本来的方式中,之所以i~j之间有点不亮走过了未曾,就是因咱们允许A连续运动了大半步,比如A从P1->P5->P6,而B可能从P1->P2。所以P3,P4我们不理解有无发出深受A或者B走至,因为我们就知A走及了P6而B走至了P2。但是若明白发现了,在正生例子中,P3、P4之后要使受B走至。所以我们改进之dp(i,j)中好让A和B一格一格走,要么A走,要么B走(其实只是吃各个生成了转而都)。
5.起矣刚的论证,我们的状态转移就改成了下面这样:
dp[i][j]=min(DP(i+1,j)+dist(i,i+1),DP(i+1,i)+dist(j,i+1));

即要A走,要么B走,如果A走的话,那么走及状态dp(i+1,j);如果B走,那么走及状态dp(i,i+1)到要求前大于后面,所以dp(i,i+1)==dp(i+1,i)即可。注意dist(i,j)表示i-j的离开。

Code

#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>

using namespace std;

struct point
{
    double x;
    double y;
};
point p[1010];

double dp[1010][1010];
double dis[1010][1010];

bool cmp(point a,point b)
{
    return a.x<b.x;
}

double dist(int i,int j)
{
    if(dis[i][j]>=0)
        return dis[i][j];
    return dis[i][j]=sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));
}

double DP(int i,int j)
{
    if(dp[i][j]>=0)
        return dp[i][j];
    dp[i][j]=min(DP(i+1,j)+dist(i,i+1),DP(i+1,i)+dist(j,i+1));
    return dp[i][j];
}

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<1010;i++)
            for(int j=0;j<1010;j++)
            {
                dis[i][j]=-1.0;
                dp[i][j]=-1.0;
            }
        for(int i=0;i<n;i++)
            cin>>p[i].x>>p[i].y;
        sort(p,p+n,cmp);
        for(int j=0;j<n;j++)
            dp[n-2][j]=dist(n-2,n-1)+dist(j,n-1);
        printf("%.2lf\n",DP(0,0));
    }
    return 0;
}

[UVA 12563] Jin Ge Jin Qu

题材叙述

发平等首杀走俏之曲,叫做”劲歌金曲”。这篇歌唱其实是37首歌唱之汇聚,长及11分叉18秒。为什么她这么红呢?假要你在KTV唱歌时单生15秒即到包场时间了,由于KTV不见面在唱歌中途来叫停,你应当及早选另一样篇曲子来延长时间。如果此刻你挑选了强硬歌金曲,那么你就会获取额外663秒的岁月……~\(≧▽≦)/~
现行而还有一对时,但是若准备制定一个计划。同时您要是满足以下规则:
1>一首歌最多只能唱一全(包括
劲歌金曲 )
2>对于同一篇长度为t的歌唱,要么唱完t时间,要么不唱
3>一篇歌唱罢晚,立即唱下一致篇(中间没有刹车)
您的靶子非常粗略,唱尽可能多的讴歌,尽可能晚的相距KTV根据第三长条规则,这吗会要我们唱太多的唱歌)。

输入

输入文件的率先实践包含一个整数T
(1<=T<=30),表示来T组测试数据。
诸一样组测试数据为个别独整数n和t
(1≤n≤50,1≤t≤10^9)开始,分别表示歌曲的数据(不包括精歌金曲)和剩余的辰。接下来的同样实行包含n个整数,分别表示马上n首讴歌的日子长短
(以秒(s)为单位,每首歌之长不超越3分钟)。
输入数据保证,所有歌唱(包括精歌金曲)的时刻总和一定超过t。

输出

对此各级一样组数据,给有尽老之歌数与歌的究竟时。

样例数据

样例输入 样例输出

2
3 100
60 70 80
3 100
30 69 70

Case 1: 2 758
Case 2: 3 777

 

 

 

 

 

 

<样例解释>

对于第一组数据,先唱80秒长之老三首,再唱678秒长的强歌金曲。
对第二组数,先唱第一首和次篇(总共99秒),此时还剩余最后1秒,我们重唱劲歌金曲(678秒)。如果我们先行唱第一篇和老三首(总共100秒),我们尽管不曾工夫唱劲歌金曲了。

解析

  每首歌唱最多选择同蹩脚,由标准180n+678>T可知最酷T=9678s,可以转账为0-1背包的问题:
  1.状态d[i][j]代表:在目前剩余时间为j的状态下,从i,i+1,…,n中能选出歌的极其充分数据。
  状态转移方程:d[i][j]=max{
d[i+1][j] , d[i+1][j-t[i]]+1 },( j-t[i]>0
);其中d[i+1][j]代表第i篇歌不选择时所选歌的无比酷数量,d[i+1][j-t[i]]+1表示第i首歌唱让选择后所选歌的最可怜数量。注意当
j-t[i]<=0 时
,即剩余时间不高于0时,第i首歌不克挑,此时d[i][j]=d[i+1][j];
  边界条件是:i>n,d[i][j]=0;
  2.由题目要求在所接触歌数目最为充分的图景下尽心尽力确保唱歌的时刻太丰富,那么等同可转正成0-1背着包问题,但是d[i][j]如若优先算:
  状态song[i][j]表示:在当前剩余时间为j的事态下,从i,i+1,…,n中所选出歌累计的极端丰富时。
  状态转移与随d[i][j]进行:令v1=d[i+1][j](即无选第i首歌唱),v2=d[i+1][j-t[i]]+1(选择第i首歌)
  如果:
    1)
v2>v1,
说明第i篇歌唱要点,song[i][j]=song[i+1][j-t[i]]+t[i];
    2)
v2==v1,
song[i][j]=max{song[i+1][j],song[i+1][j-t[i]]+t[i]};
    3)
v2<v1,
说明第i首歌唱一定非可知接触,song[i][j]=song[i+1][j];
  逆序递推,答案是d[1][T]和song[1][T]。

Code

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const int INF=-100000000;
const int maxn=50;
const int maxt=10000;

int t[maxn+5];
int d[maxn+5][maxt];
int song[maxn+5][maxt];
int n,T;

int main()
{
    int Case;
    scanf("%d",&Case);
    for(int tt=1;tt<=Case;tt++)
    {
        scanf("%d%d",&n,&T);
        memset(t,0,sizeof t);
        for(int i=1;i<=n;i++)
            scanf("%d",&t[i]);
        memset(d,0,sizeof d);
        memset(song,0,sizeof song);
        for(int j=T;j>=0;j--)
        {
            if(j-t[n]>0)
                song[n][j]=t[n];
            else
                song[n][j]=0;
        }
        for(int i=n;i>=1;i--)
            for(int j=T;j>0;j--)
            {
                int v1,v2;
                v1=d[i+1][j];
                if(j-t[i]<=0)
                    v2=INF;
                else
                    v2=d[i+1][j-t[i]]+1;
                d[i][j]=max(v1,v2);
                if(v2>v1)
                    song[i][j]=song[i+1][j-t[i]]+t[i];
                else if(v2==v1)
                    song[i][j]=max(song[i+1][j],song[i+1][j-t[i]]+t[i]);
                else
                    song[i][j]=song[i+1][j];
            }
        int num=d[1][T]+1;
        int len=song[1][T]+678;
        printf("Case %d: %d %d\n",tt,num,len);
    }
    return 0;
}

[UVA 11400] Lighting System Design

问题叙述

你就要为一个议会大厅设计一个照明系统。在召开了有考察暨计量后,你意识发一个仔细的计划性能够满足大厅的照明需求。根据这同一规划,你用n种不同功率的电灯。由于电流调节需要,所有的电灯都用被通过平等之电流,因此,每一样栽灯都来相应之额定电压。现在,你都清楚了各个一样种植电灯的数量与单位成本。但问题来了,你将要为有着品种的灯泡买同样的电源。事实上,你吗可以吧每一样种灯泡单独购买同样栽电源(我们认为:一个电源可以呢多独额定电压啊电源电压的电灯供电)来好计划。但是商家财务部很快发现他们可以通过删除一些电源并转移高功率的灯泡。你自不可知将灯泡换成低功率的,因为这么就是会见要大厅的平局部不能够取得照明。你再次体贴的凡省钱而休是节约能源,因此你如果重新设计一个系(将有低位电压灯泡更换也大电压灯泡),来而价格不过方便。

输入

发出差不多组数。
诸一样组数据以一个整数n
(1<=n<=1000),表示灯泡的种类。接下来的n行每一行表示一致种灯泡的音,一行包含4只整数:额定电压V
(1<=V<=132000),满足所欲电压的电源的单价K
(1<=K<=1000),灯泡的单价C (1<=C<=10),需要之灯泡数量L
(1<=L<=100)。
当n=0时,输入数据了。

输出

于各一样组数据,输出可能的极度小花费。

样例数据

样例输入 样例输出

3
100 500 10 20
120 600 8 16
220 400 7 18
0

778

 

 

 

 

 

 

解析

率先要明白一栽灯泡要全部转移,要么不移。如果换一部分吧,首先电源费用得不至节,那么节省的有的就光来于转换的那有些灯泡,既然可以省钱干嘛不干脆全部更换了吗?所以要全换,要么不转换。然后我们的算法就是事先随V排序,然后cost[i]代表解决眼前
i
种灯泡的最优解,那么换方程是枚举j<i,将j之前的保障最好优解cost[j]莫换,j之后的整个成为i种灯泡。开始发出一个狐疑是:会不见面漏解,为什么没有枚举替换j之前的莫总是的均等片?后来发现,这个题目莫过于不在,因为i之前的灯泡肯定是越来越后面的费逾怪,因为要前的消费反而更可怜的话语,大可换为后的灯泡。

Code

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>

#define INF 0x3f3f3f3f
#define MAXN 1010

using namespace std;

struct node
{
    int v,k,c,l;
};
node light[MAXN];

bool cmp(node a,node b)
{
    return a.v<b.v;
}

int num[MAXN];
int cost[MAXN];

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF&&n!=0)
    {
        for(int i=1;i<=n;i++)
            cin>>light[i].v>>light[i].k>>light[i].c>>light[i].l;
        sort(light+1,light+n+1,cmp);
        num[0]=0;
        for(int i=1;i<=n;i++)
        {
            num[i]=num[i-1]+light[i].l;
        }
        cost[0]=0;
        for(int i=1;i<=n;i++)
        {
            cost[i]=INF;
            for(int j=0;j<=i;j++)
                cost[i]=min(cost[i],cost[j]+(num[i]-num[j])*light[i].c+light[i].k);
        }
        cout<<cost[n]<<endl;
    }
    return 0;
}

[UVA 1625] Color Length

题目叙述

输入两独长分别吗n和m(n,m≤5000)的颜色序列,要求按序列合并成同一个阵,即每次可拿一个队列开头的水彩放到新序列的尾。例如,两独颜色序列GBBY和YRRGB,至少有点儿种植合并结果:GBYBRYRGB和YRRGGBBYB。对于每个颜色c来说,其跨度L(c)等于最充分职务以及极其小位置的异。例如,对于地方两栽合并结果,每个颜色之L(c)和所有L(c)的总和如图所示。你的职责是寻觅一种合并方式,使得所有L(c)的总和最小。(注:该英文翻译来自《算法竞赛入门经典(第2本)》)

威尼斯人官网 1

输入

输入文件包含了T组测试数据,T在输入数据的第1实施会为起。
每一样组测试数据包含两尽字符串,各代表一个颜色序列。在字符串中,颜色用小写英文字母表示。
输入数据保证:每组数据中冒出的水彩数不超越26,每一个颜料序列的长短不越5000。

输出

对各一样组测试数据,输出一个整数,表示L(c)的总和的无限小价。

样例数据

样例输入 样例输出

2
AAABBCY
ABBBCDEEY
GBBY
YRRGB

10
12

 

 

 

 

 

解析

对此个别个颜色序列p和q,设d(i,j),表示p拿前i个字符,q拿前j个字符所要之代价。
由于n,m<=5000,二维数组改成为滚动数组。
其一时候,不是相等交一个颜料全部活动了了以后再算跨度,而是,只要稍微种颜色都上马只是没有终了,就L(c)+1;
首要在于求代价C。首先计算全部移动q,只要是欠字符开头,代价就是加同,但是若刚好是终极一个就是恢复。然后再度推数组p时,就可以一直动用就算好的c代价数组,只待依据它们创新由于i的投入如增加的代价。

Code

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>

#define maxn 5005
#define INF 0x3f3f3f3f

using namespace std;

char p[maxn],q[maxn];
int sp[26],ep[26],sq[26],eq[26];
int d[2][maxn],c[2][maxn];

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s%s",p+1,q+1);
        int n=strlen(p+1);
        int m=strlen(q+1);
        for(int i=1;i<=n;i++)
            p[i]-='A';
        for(int i=1;i<=m;i++)
            q[i]-='A';
        for(int i=0;i<26;i++)
        {
            sp[i]=sq[i]=INF;
            ep[i]=eq[i]=0;
        }
        for(int i=1;i<=n;i++)
        {
            sp[p[i]]=min(sp[p[i]],i);
            ep[p[i]]=i;
        }
        for(int i=1;i<=m;i++)
        {
            sq[q[i]]=min(sq[q[i]],i);
            eq[q[i]]=i;
        }
        memset(c,0,sizeof(c));
        memset(d,0,sizeof(d));
        int t=1;
        for(int i=0;i<=n;i++)
        {
            for(int j=0; j<=m;j++)
            {
                if(!i&&!j)
                    continue;
                int v1=INF,v2=INF;
                if(i)
                    v1=d[t^1][j]+c[t^1][j];
                if(j)
                    v2=d[t][j-1]+c[t][j-1];
                d[t][j]=min(v1, v2);
                if(i)
                {
                    c[t][j]=c[t^1][j];
                    if(sp[p[i]]==i&&sq[p[i]]>j)
                        c[t][j]++;
                    if(ep[p[i]]==i&&eq[p[i]]<=j)
                        c[t][j]--;
                }
                else if(j)
                {
                    c[t][j]=c[t][j-1];
                    if(sq[q[j]]==j&&sp[q[j]]>i)
                        c[t][j]++;
                    if(eq[q[j]]==j&&ep[q[j]]<=i)
                        c[t][j]--;
                }
            }
            t^=1;
        }
        printf("%d\n",d[t^1][m]);
    }
    return 0;
}

[UVA 10003] Cutting Sticks

题目叙述

汝的职责是给一小叫Analog
Cutting Machinery (ACM)的局切割木棍。
切割木棍的本金是基于木棍的长要迟早。 而且切割木棍的当儿每次仅切一段子。

杀明显的,不同切割的逐条会发生例外的基金。
例如: 有雷同到底长10公尺的木棒必须于第2、4、7公尺的地方切割。
这个时就是出几种植选择了。你可选择先切2公尺的地方,
然后切4公尺之地方,最后切7公尺的地方。这样的挑选那个基金也:10+8+6=24。
因为第一次等切时木棍长10米,第二不成切时木棍长8公尺,第三次于切时木棍长6公尺。
但是只要你挑选先切4公尺之地方,然后切2公尺的地方,最后切7公尺之地方,
其资本为:10+4+6=20,这本就是一个较好之精选。
君的业主相信您的计算机能力自然得找寻来切割一木棒所欲最小之财力。

同样句子话题意:给得一干净已知道长度的木棒,给定n个切割点,要求仍切割点切割木棍,花费按照切割的木棒长度计算,例如有一样彻底长10底木棍,切割点为2、4、7,如果照2、4、7底相继切割,花费将凡10

  • 8 + 6 = 24,如果依照4、2、7之依次切割,那么花费将是10 + 4 + 6 =
    20,切割顺序可以随心所欲,要求花费最小。

输入

饱含多组测试数据。
对每组测试数据:第1履行包含一个正整数l
(l<1000),表示木棍的总长度。第2实践被起刚刚整数n
(n<50),表示切割点的数据。第3尽仍升序给出n个刚刚整数ci
(0<ci<l),表示每一个切割点的位置。
当l=0时,输入数据截止。

输出

对于每一样组测试数据,输出完成切割的不过小花费。输出格式见样例。

样例数据

样例输入 样例输出

100
3
25 50 75
10
4
4 5 7 8
0

The minimum cutting is 200.
The minimum cutting is 22.

 

 

 

 

 

 

 

解析

较独立的动态规划问题,根据题意找到状态转移公式就吓了:dp[i][j]=max{dp[i][k]+dp[k][j]+len[j]-len[i]|i<k<j} 

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>

const int INF = 0x3f3f3f3f;

using namespace std;

int dp[100][100];
int num[100];

int main()
{
    int len,n;
    while(scanf("%d",&len)&&len)
    {
        scanf("%d",&n);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
            scanf("%d",&num[i]);
        num[0]=0;
        num[n+1]=len;
        int minn,p;
        for(int i=1;i<=n+1;i++)
        {
            for(int j=0;j+i<=n+1;j++)
            {
                p=j+i;
                minn=INF;
                for(int k=j+1;k<p;k++)
                {
                    int temp=dp[j][k]+dp[k][p]+num[p]-num[j];
                    if(temp<minn)
                        minn=temp;
                }
                if(minn!=INF)
                    dp[j][p]=minn;
            }
        }
        printf("The minimum cutting is %d.\n",dp[0][n+1]);
    }
    return 0;
}

[POJ 1141] Brackets Sequence

问题叙述

咱们觉得一个括号序列是起规律的,需满足以下条件:
1.一个拖欠的行列是发生规律的;
2.如果S是生规律的括号序列,那么(S)和[S]且是出规律的括号序列;
3.比方果A和B都是起规律的括号序列,那么AB也是来规律的括号序列。
选举个例,一下之装有括号序列都是发出规律的:
(), [], (()),
([]), ()[], ()[()]
假若以下的括号序列都未是:
(, [, ), )(,
([)], ([(]
于有一个富含'(‘,
‘)’, ‘[‘, 和
‘]’的序列S,你而找到最好短缺的发出规律的括号序列,使S成为那个字串。

输入

输入文件最多带有100独充满如泣如诉字符(仅含'(‘,
‘)’, ‘[‘, 和 ‘]’)。

输出

出口找到的括号序列。

样例数据

样例输入 样例输出
([(] ()[()]

 

 

 

解析

用DP求最少要充满号数:以p从1到n(字符串长度),记录下由i到i+p需要丰富的极端少括号数f[i][j],同时记录下中用加加括号的职务pos[i][j]——为-1表示不待丰富。

Code

#include<cstdio>
#include<cstring>

#define MAXN 120

const int INF=0x7fffffff;

int f[MAXN][MAXN],pos[MAXN][MAXN];
char s[MAXN];

int n;

int DP()
{
    n=strlen(s);
    memset(f,0,sizeof(f));
    for(int i=n;i>0;i--)
    {
        s[i]=s[i-1];
        f[i][i]=1;
    }
    int tmp;
    for(int p=1;p<=n;p++)
    {
        for(int i=1;i<=n-p;i++)
        {
            int j=i+p;
            f[i][j]=INF;
            if((s[i]=='('&&s[j]==')')||(s[i]=='['&&s[j]==']'))
            {
                tmp=f[i+1][j-1];
                if(tmp<f[i][j])
                    f[i][j]=tmp;
            }
            pos[i][j]=-1;
            for(int k=i;k<j;k++)
            {
                tmp=f[i][k]+f[k+1][j];
                if(tmp<f[i][j])
                {
                    f[i][j]=tmp;
                    pos[i][j]=k;
                }
            }
        }
    }
    return f[1][n];
}

void print(int beg,int End)
{
    if(beg>End)
        return ;
    if(beg==End)
    {
        if(s[beg]=='('||s[beg]==')')
            printf("()");
        else
            printf("[]");
    }
    else
    {
        if(pos[beg][End]==-1)
        {
            if(s[beg]=='(')
            {
                printf("(");
                print(beg+1,End-1);
                printf(")");
            }
            else
            {
                printf("[");
                print(beg+1,End-1);
                printf("]");
            }
        }
        else
        {
            print(beg,pos[beg][End]);
            print(pos[beg][End]+1,End);
        }
    }
}

int main()
{
    scanf("%s",s);
    DP();
    print(1,n);
    return 0;
}

<这里出一个坑一点之变式:UVALive
2451,你可修改这道题之代码再付,随意感受一下>

威尼斯人官网 2威尼斯人官网 3

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cmath>

#define MAXN 120

using namespace std;

const int INF=0x7fffffff;

int f[MAXN][MAXN],pos[MAXN][MAXN];
char s[MAXN];

int n;

void Clear()
{
    memset(pos,0,sizeof(pos));
    memset(s,0,sizeof(s));
    n=0;
}

int DP()
{
    n=strlen(s);
    memset(f,0,sizeof(f));
    for(int i=n;i>0;i--)
    {
        s[i]=s[i-1];
        f[i][i]=1;
    }
    int tmp;
    for(int p=1;p<=n;p++)
    {
        for(int i=1;i<=n-p;i++)
        {
            int j=i+p;
            f[i][j]=INF;
            if((s[i]=='('&&s[j]==')')||(s[i]=='['&&s[j]==']'))
            {
                tmp=f[i+1][j-1];
                if(tmp<f[i][j])
                    f[i][j]=tmp;
            }
            pos[i][j]=-1;
            for(int k=i;k<j;k++)
            {
                tmp=f[i][k]+f[k+1][j];
                if(tmp<f[i][j])
                {
                    f[i][j]=tmp;
                    pos[i][j]=k;
                }
            }
        }
    }
    return f[1][n];
}

void print(int beg,int End)
{
    if(beg>End)
        return ;
    if(beg==End)
    {
        if(s[beg]=='('||s[beg]==')')
            printf("()");
        else
            printf("[]");
    }
    else
    {
        if(pos[beg][End]==-1)
        {
            if(s[beg]=='(')
            {
                printf("(");
                print(beg+1,End-1);
                printf(")");
            }
            else
            {
                printf("[");
                print(beg+1,End-1);
                printf("]");
            }
        }
        else
        {
            print(beg,pos[beg][End]);
            print(pos[beg][End]+1,End);
        }
    }
}

int main()
{
    int num;
    scanf("%d",&num);
    getchar();
    for(int i=1;i<=num;i++)
    {
        Clear();
        gets(s);
        gets(s);
        DP();
        print(1,n);
        if(i!=num)
            printf("\n\n");
        else
            printf("\n");
    }
    return 0;
}

View Code

[UVA 1331] Minimax Triangulation

问题叙述

照顺时针或者逆时针的相继为出多边的点,要以以此多边形分解成n-2只三角形,要求令这些三角行中面积不过特别的三角形面积尽量小,求最好小价。

输入

输入文件包含多组数。输入文件之第1行包含一个整数n,表示有n组数据。
于各一样组数据,第1履包含一个平头m
(2<m<50),表示该多边形有m个顶点。接下来的m行,每行包含两个整数x和y
(0<=x,y<=10000),表示一个终极的坐标。

输出

对各一样组数,输出面积之无比小价,答案保留一员小数。

样例数据

样例输入 样例输出

1
6
7 0
6 2
9 5
3 5
0 3
1 1

9.0

 

 

 

 

 

 

 

 

解析

状态十分好怀念,dp[i][j]表示从第i个点交第j单点,划分成j-i-1只三角的太优解,然后每次更换时,枚举长度以及不当边界始点,那么根据长度及左手界点就可以知道右边界点,然后枚举左边界和右侧边界中的点k,dp[i][j]
= min(dp[i][j], max(max(dp[i][k], dp[k][j]), Area(i, k,
j)).但是生一个题材,即i,k,j三碰围成的三角是否符合要求,判断的口径就是为是否存在除i,k,j三沾外的一些在三角形中,有面积法判断。

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;
const int N=100;
const double INF=0x3f3f3f3f3f3f;
const double eps=1e-9;

struct point
{
    double x,y;
    void get()
    {
        scanf("%lf%lf",&x,&y);
    }
}p[N];

int n;
double dp[N][N];

double area(point a,point b,point c)
{
    return fabs((b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y))/2;
}

bool judge(int a,int b,int c)
{
    double cur=area(p[a],p[b],p[c]);
    for(int i=0;i<n;i++)
    {
        if(i==a||i==b||i==c)
            continue;
        double tmp=area(p[a],p[b],p[i])+area(p[b],p[c],p[i])+area(p[c],p[a],p[i]);
        if (fabs(tmp-cur)<eps)
            return false;
    }
    return true;
}

double solve ()
{
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<n;j++)
            dp[j][(j+i)%n]=0;
    }
    for(int i=0;i<n;i++)
        dp[i][(i+2)%n]=area(p[i],p[(i+1)%n],p[(i+2)%n]);
    for(int k=3;k<n;k++)
    {
        for(int i=0;i<n;i++)
        {
            int t=(i+k)% n;
            dp[i][t]=INF;
            for(int j=(i+1)%n;j!=t;j=(j+1)%n)
            {
                if(judge(i,t,j))
                    dp[i][t]=min(dp[i][t],max(max(dp[i][j],dp[j][t]),area(p[i],p[j],p[t])));
            }
        }
    }
    double ans=INF;
    for(int i=0;i<n;i++)
        ans=min(ans,dp[i][(i+n-1)%n]);
    return ans;
}

int main ()
{
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            p[i].get();
        printf("%.1lf\n",solve());
    }
    return 0;
}

[UVA 12186] Another Crisis

问题叙述

世界危机产生了,工人等请加薪。一个老板和n个员工组成树状结构,每个职工还发出和好之绝无仅有上司,Boss的号为0,员工1~n,工人等打算签署一个志愿书给老板,但无能为力跨级,当一个中间员工(非是工人的员工)的隶属下属吃不小于T%的丁签名时,他吧会见签署又递交他的依附上司,问:要叫Boss收到请愿书至少需要有些只工人签字?

输入

输入文件包含多组数据,每一样组测试数据占少数实行。
于各级一样组测试数据:第1实践包含两单整数N和T
(1≤N≤10^5,1≤T≤100),其中N表示公司里之员工反复(不包括Boss),T的义见题目叙述;第2履行包含N个整数Bi
(0<=Bi<=i-1),表示编号为i的职工的直系Boss是编号为Bi的职工。
当N=0且T=0时,输入文件截止。

输出

对各一样组测试数据,输出需要签的无限少员工数。

样例数据

样例输入 样例输出

3 100
0 0 0
3 50
0 0 0
14 60
0 0 1 1 2 2 2 5 7 5 7 5 7 5
0 0

3
2
5

 

 

 

 

 

 

 

 

解析

设d[u]代表让u给上级发信最少要多少只工人。假设u有k个子节点,则最少要c=(k*T-1)/100+1单一直下属发信才行。把所有子节点的d值从小到非常排序,前c个加起来即可。最终答案是d[0]。

Code

#include<vector>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>

using namespace std;

const int maxn=100000+5;

int n,t;
vector<int> sons[maxn];

int dp(int u)
{
    if(sons[u].empty())  
        return 1;
    vector<int> d;
    int k=sons[u].size();
    for(int i=0;i<k;i++)
        d.push_back(dp(sons[u][i]));
    sort(d.begin(),d.end());
    int c=(k*t-1)/100+1;
    int ans=0;
    for(int i=0;i<c;i++)
        ans+=d[i];
    return ans;
}

int main()
{
    int temp;
    while(scanf("%d%d",&n,&t)&&(n||t))
    {
        for(int i=0;i<=n;i++)
            sons[i].clear();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&temp);
            sons[temp].push_back(i);
        }
        int ans=dp(0);
        printf("%d\n",ans);
    }
    return 0;
}

[POJ 3398] Perfect Service

题材叙述

N台电脑由N-1长达连线连接,使得任意两光微机都能够由此平等长道联系,这样即使形成了网络。如果简单玉计算机内发生同样修线连接,那么我们说立刻片令计算机相邻。所有和平等高微机相邻之处理器组成的集结,我们称为邻居。为了能够迅速地存取接收大量的信,我们需要以一些处理器成为服务器,来为它们抱有的邻里提供资源。如果以一个网中,所有的用户(即未是服务器的微机)都吃正好一个服务器提供资源,我们虽看是网络形成了健全服务。现在我们定义,使一个网络形成完善服务所欲的最好少之服务器的多寡,叫做”宏观服务数“。

俺们借设有N台电脑,且拿电脑由1~N编号。例如Figure
1所著之大网由6高微机组成,其中的非官方点表示服务器,白点表示用户。在Figure
1(a)中,3如泣如诉和5号服务器无变异健全服务,因为4号用户同时让简单独服务器覆盖至了。而在Figure
1(b)中,3哀号与4号服务器即形成了完善服务,这个例子中的”完美服务数”就当2。

威尼斯人官网 4

您的天职是描摹一个主次计算产生”完美服务数”。

输入

输入文件包含多组数。
对此每一样组数:第一履包含一个刚好整数N
(1<=N<=10000),表示网络中之电脑数。接下来的N-1行,每一行都蕴含两只正整数Ai和Bi,表示Ai和Bi是相邻之。第N+1行之”0″表示第一组数据的结束,接着开输入下一个数。当一组数的最终给出”-1″时,表示所有之输入数据了。

输出

对于各一样组测试数据,输出计算出底”完美服务数”。

样例数据

样例输入 样例输出

6
1 3
2 3
3 4
4 5
4 6
0
2
1 2
-1

2
1

 

 

 

 

 

 

 

 

 

解析

dp[i][0]意味着i是服务器又因为i为根之子树都受掩的景下服务器的卓绝少沾数 
dp[i][1]意味着i不属服务器,且因为i为根本之子树都吃挂,且i被里面不少于一个子节点覆盖的气象下服务器的顶少沾数 
dp[i][2]代表i不属服务器,且因为i为根本之子树都为蒙,且i没被子节点覆盖的状下服务器的极度少碰数 
dp[i][0]=1+sum(min(dp[u][0],dp[u][2])) 
dp[i][1]=INF
当i没有子节点 
dp[i][1]=sum(min(dp[u][0],dp[u][1]))+inc
当i有子节点 
inc=0若sum(min(dp[u][0],dp[u][1]))包含有dp[u][0] 
否则inc=min(dp[u][0]-dp[u][1]) 
dp[i][2]=sum(dp[u][1]) 
结果就为min(dp[1][0],dp[1][1]) 

Code

#include<cstdio>
#include<iostream>
#include<cstring>

#define maxn 11111
#define INF 0x3f3f3f3f
#define ll long long

using namespace std;

struct Edge
{
    int to;
    int next;
}edge[2*maxn];

int n,head[maxn],tot;
int dp[maxn][3];

void init()
{
    tot=0;
    memset(head,-1,sizeof(head));
    for(int i=0;i<maxn;i++)
        dp[i][1]=INF;
}

void add(int u,int v)
{
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}

void DP(int u,int fa)
{
    dp[u][0]=1,dp[u][2]=0;
    int sum=0,inc=INF,flag=0;
    for(int i=head[u];~i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==fa)
            continue;
        DP(v,u);
        dp[u][0]+=min(dp[v][0],dp[v][2]);
        if(dp[v][0]<=dp[v][1])
            sum+=dp[v][0],flag=1;
        else 
            sum+=dp[v][1],inc=min(inc,dp[v][0]-dp[v][1]);
        if(dp[v][1]!=INF&&dp[u][2]!=INF)
            dp[u][2]+=dp[v][1];
        else 
            dp[u][2]=INF;
    }
    if(inc!=INF&&!flag)
        dp[u][1]=INF;
    else
    {
        dp[u][1]=sum;
        if(!flag)
            dp[u][1]+=inc;
    }
}

int main()
{
    while(~scanf("%d",&n))
    {
        init();
        int u,v,t;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        DP(1,1);
        int ans=min(dp[1][0],dp[1][1]);
        printf("%d\n",ans);
        scanf("%d",&t);
        if(t!=0)
            break;
    }
    return 0;
}

[POJ 3570 | UVA 1412] Fund Management

问题叙述

Frank从个体投资者获得了c美元的本,可用于m天的投资。
Frank可以对n支股票进行投资。对于各一样开发股票:都起一个交易达到限si,表示无异天无限多能交易的股数;还有一个上限ki,表示Frank最多可具有的股数。对于具有项目的股票,同样来一个直达限k表示Frank可同时有的顶酷股数。
股票的市还满足一下要求:
1>一天无限多只能进行同样潮交易(你呢足以免交易);
2>若使针对性第i开销股票进行选购或卖掉,只能一次性购买还是售Si股;
3>所有的贸易还是在Frank有足的本钱之标准化下成功的;
4>当m天过去晚,Frank的成本要尽转账为现金,不可知在股票市场里,(m天中,股票必须全部卖出)。
现行,给来各一样开销股票的各个一样上的价钱,要求您算出Frank能回收的本之顶可怜价值,并让出各一样天之切实的操作方法。

输入

第1实行:包含四独数c,m,n,k:c  (0.01
≤ c ≤ 100 000 000.00)表示无异开始享有的财力,最多片员小数;m (1 ≤m ≤
100)表示足交易的造化;n (1 ≤ n ≤ 8)表示股票的种数;k (1 ≤ k ≤
8)表示有股票的绝多备的股数。

通下去的2n行:描述每一样支付股票的音讯(一支出股票占2行)。对于各一样开支股票:第1实践:包含股票名称(一个五位以内的死去活来写字母组成的字符串),si(1
≤ si ≤ 1 000 000,一龙之极端酷交易量),ki(1 ≤ ki ≤
k,该股票的不过可怜有所股数);第2履:包含m
个小数(0.01<=m<=999.99,二各项小数以内),表示股票各一样天的价钱。

输出

输出文件包含m+1行。第1执行:回收成本的绝深价值;第2~m+1履,每一样上之操作。具体格式见样例。

样例数据

样例输入 样例输出
144624.00 9 5 3
IBM 500 3
97.27 98.31 97.42 98.9 100.07 98.89 98.65 99.34 100.82
GOOG 100 1
467.59 483.26 487.19 483.58 485.5 489.46 499.72 505 504.28
JAVA 1000 2
5.54 5.69 5.6 5.65 5.73 6 6.14 6.06 6.06
MSFT 250 1
29.86 29.81 29.64 29.93 29.96 29.66 30.7 31.21 31.16
ORCL 300 3
17.51 17.68 17.64 17.86 17.82 17.77 17.39 17.5 17.3
151205.00
BUY GOOG
BUY IBM
BUY IBM
HOLD
SELL IBM
BUY MSFT
SELL MSFT
SELL GOOG
SELL IBM

 

 

 

 

 

 

 

 

 

解析

共计发n天,把命运看作阶段,对于各一样上,我们可择出手或进货进一手股票,在结尾一上要用股票全部出手还求解最深钱数。
足这样定义d[i][s]:表示第i天手中股票的状态也s时手中的极度深钱数,采用刷表法更新d[i+1][s’],s’表示s经过出手或购买转移的状态。
题材便成了什么表示状况s?采用n元组的样式。
然未克拿一个n元组表示进d数组,这里的方法是离线dfs出任何态并分别编号,得出状态和不断的涉buy_next与sell_next。那么d中的状态s就足以为此一个平头表示了。
此外输出为来得的技术,用到了pre与opt数组,并据此长区别操作。

Code

#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<map>
#include<vector>

#define maxn 110
#define INF 0X3F3F3F3F

using namespace std;

double C;
int M,N,K;
char name[10][maxn];
int k[maxn];
double d[10][maxn];

map <vector<int>,int>ID;
vector <vector<int> >states;

double bn[15000][10];
double sn[15000][10];
double dp[maxn][15000];
int opt[maxn][15000],pre[maxn][15000];

void dfs(int day,vector<int>& lots,int tot)
{
    if(day==N)
    {
        ID[lots]=states.size();
        states.push_back(lots);
        return;
    }
    for(int i=0;i<=k[day]&&i+tot<=K;i++)
    {
        lots[day]=i;
        dfs(day+1,lots,tot+i);
    }
}

void ud(int day,int s,int s2,double v,int o)
{
    if(v>dp[day+1][s2])
    {
        dp[day+1][s2]=v;
        opt[day+1][s2]=o;
        pre[day+1][s2]=s;
    }
}

void print_ans(int day,int s)
{
    if(day==0) 
        return;
    print_ans(day-1,pre[day][s]);
    if(opt[day][s]==0) 
        printf("HOLD\n");
    else if(opt[day][s]>0) 
        printf("BUY %s\n",name[opt[day][s]-1]);
    else 
        printf("SELL %s\n",name[-opt[day][s]-1]);
}

int main()
{
    while(scanf("%lf %d %d %d",&C,&M,&N,&K)!=EOF)
    {
        double temp;
        for(int i=0;i<N;i++)
        {
            scanf("%s %lf %d",name[i],&temp,&k[i]);
            for(int j=0;j<M;j++)
            {
                scanf("%lf",&d[i][j]);
                d[i][j]*=temp;
            }
        }
        ID.clear();
        states.clear();
        vector<int>lots(N);
        dfs(0,lots,0);
        for(unsigned int s=0;s<states.size();s++)
        {
            int tot=0;
            for(int i=0;i<N;i++)
            {
                bn[s][i]=sn[s][i]=-1;
                tot+=states[s][i];
            }
            for(int i=0;i<N;i++)
            {
                if(states[s][i]<k[i]&&tot<K)
                {
                    vector<int> news=states[s];
                    news[i]++;
                    bn[s][i]=ID[news];
                }
                if(states[s][i]>0)
                {
                    vector<int> news=states[s];
                    news[i]--;
                    sn[s][i]=ID[news];
                }
            }
        }
        for(int day=0;day<=M;day++)
            for(unsigned int s=0;s<states.size();s++) dp[day][s]=-INF;
        dp[0][0]=C;
        for(int day=0;day<M;day++)
            for(unsigned int s=0;s<states.size();s++)
            {
                double v=dp[day][s];
                if(v<-1) continue;
                ud(day,s,s,v,0);
                for(int i=0;i<N;i++)
                {
                    if(bn[s][i]>=0&&v>=d[i][day]-1e-3)
                        ud(day,s,bn[s][i],v-d[i][day],i+1);
                    if(sn[s][i]>=0)
                        ud(day,s,sn[s][i],v+d[i][day],-i-1);
                }
            }
        printf("%.2lf\n",dp[M][0]);
        print_ans(M,0);
    }
    return 0;
}

[UVA 10618] Tango Tango Insurrection

问题叙述

公想模仿在玩跳舞机。跳舞机的踏板上产生四个箭头:上、下、左、右。当舞曲开始经常见面发出一部分箭头往上移步。当发展移动的箭头与顶部的箭头模板重合时,你待为此脚踩一下踏板上的同箭头。不欲踩箭头时,踩箭头不见面遭惩处,但当得踩箭头时必须踩一下,哪怕曾生同一单独下在了该箭头上。很多舞曲速度飞快,需要来回倒腾步子。因此只要描写一个程序,来选最好自在的踩踏方式,使得消耗的能量最少。
以八分音符作为一个中心时间单位,每个时刻单位还是得踩一个箭头(不见面同时要求踩两只箭头),要么什么还无待踩。在自由时刻,你的横下应放在两只不同的箭头上,且每个时刻单位内仅出雷同只脚能动(移动
和/或
踩箭头),不可知蹦。另外,你得面朝前方为盼屏幕(例如,你切莫可知左脚在右箭头上,右脚在左箭头上)。
当你尽一个动作(移动还是踩踏)时,消耗的能量这样测算:
◎如果就就脚上个日子单位从来不其他动作,消耗1单位能;
◎如果当时只有脚上单时刻单位从未动,消耗3单位能;
◎如果立即单脚上单日子单位活动到相邻箭头,消耗5单位能;
◎如果立刻不过下上只时刻单位活动及相对箭头,消耗7单位能。
健康状态下,你的左脚不能够放在右箭头上(或者反的),但出一样栽状态不同:如果你的左脚在直达箭头或下箭头,你可以就此右边下踹左箭头,但是以您的右边下移出荒唐箭头之前,你的左脚都不能够转换到其它一个箭头上。右下的情况以此类推。
同等开始,你的左脚在左箭头上,右脚在右侧箭头上。

威尼斯人官网 5                     
 威尼斯人官网 6

          跳舞机踏板                                      跳舞机屏幕

输入

输入文件最多含有100组数,每组数据包含一个长不越70的字符串,即各个时间单位要踩的箭头。L和R分别表示左右箭头,U和D分别代表上下箭头,’.’表示未待踩箭头。

输出

出口应是一个尺寸以及输入相同之字符串,表示每个时刻单位执行动作之脚。L和R分别是反正下,’.’代表未登。

样例数据

样例输入 样例输出

LRLRLLLLRLRLRRRRLLRRLRLDU…D…UUUUDDDD
#

LRLRLLLLRLRLRRRRLLRRLRLRL…R…LLLLRRRR

 

 

 

 

解析

于屏幕上之职位要产生平等下面踩下,对个别底下位置有求且根据脚的移位关系分配代价,求好屏幕要求的状下代价不过小。
用状态d[i][a][b][s]意味着早已踩过i只指令,左右脚位置为ab,因为用基于当下倒的下是否刚动了用用s表示上次移动的下边。
状态转移方程:
d[i][a][b][s]=min(d[i][ta][tb][s’]+cost)
然注意到,expr是现阶段之移位,移动继换到i+1且岗位成移动后的岗位,
因此用倒序枚举i,把i+1看作是 i 的道岔问题
原来char[]得这么用。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

#define MAXN 75
#define INF 0x3f3f3f3f

struct NODE
{
    int i,l,r,s;
}path[MAXN][4][4][3];

char a[MAXN];
int dp[MAXN][4][4][3],n,buf;

bool ok(int f,int l,int r,int to)
{
    if (0==f)
    {
        if(to==r) 
            return false;
        if(to==l) 
            return true;
        if(2==r) 
            return false;
    }
    else
    {
        if(to==l) 
            return false;
        if(to==r)
            return true;
        if(3==l) 
            return false;
    }
    return true;
}

int cost(int s,int now,int from,int to)
{
    if(s!=now) 
        return 1;
    if(from==to) 
        return 3;
    if((from==0&&to==1)||(from==1&&to==0)) 
        return 7;
    if((from==2&&to==3)||(from==3&&to==2))
        return 7;
    return 5;
}

int dfs(int i,int l,int r,int s)
{
    int& ans=dp[i][l][r][s];
    NODE& p=path[i][l][r][s];
    if(-1!=ans) 
        return ans;
    if(i==n) 
        return ans = 0;
    ans=INF;
    if('.'==a[i])
    {
        ans=min(ans,dfs(i+1,l,r,0));
        p.i=i+1,p.l=l,p.r=r,p.s=0;
        for(int j=0;j<4;j++)
        {
            if(ok(0,l,r,j))
            {
                buf=dfs(i+1,j,r,1)+cost(s,1,l,j);
                if(ans>buf)
                    ans=buf,p.i=i+1,p.l=j,p.r=r,p.s=1;
            }
            if(ok(1,l,r,j))
            {
                buf=dfs(i+1,l,j,2)+cost(s,2,r,j);
                if(ans>buf)
                    ans=buf,p.i=i+1,p.l=l,p.r=j,p.s=2;
            }
        }
        return ans;
    }
    int to;
    switch(a[i])
    {
    case 'U':to=0; break;
    case 'D':to=1; break;
    case 'L':to=2; break;
    case 'R':to=3; break;
    }
    if(ok(0,l,r,to))
    {
        buf=dfs(i+1,to,r,1)+cost(s,1,l,to);
        if(ans>buf)
            ans=buf,p.i=i+1,p.l=to,p.r=r,p.s=1;
    }
    if(ok(1,l,r,to))
    {
        buf=dfs(i+1,l,to,2)+cost(s,2,r,to);
        if(ans>buf)
            ans=buf,p.i=i+1,p.l=l,p.r=to,p.s=2;
    }
    return ans;
}

void pt(int i,int l,int r,int s)
{
    if(n==i) 
        return;
    NODE& p=path[i][l][r][s];
    if(!p.s)
        printf(".");
    else if(p.s==1)
        printf("L");
    else
        printf("R");
    pt(p.i,p.l,p.r,p.s);
}

int main()
{
    while(scanf("%s%*c",a)&&'#'!= a[0])
    {
        n=strlen(a);
        memset(dp,-1,sizeof(dp));
        dfs(0,2,3,0);
        pt(0,2,3,0);
        puts("");
    }
    return 0;
}

[UVA 10934] Dropping Water Balloons

问题叙述

若闹k个一模一样的水球,在一个n层楼的建筑上拓展测试,你想了解水球最低打几叠楼向下丢好为水球破掉。由于你怪懒,所以你想只要摒弃尽少次水球来测量出水球刚好破掉的低楼层。(在最好浅情况下,水球在顶楼也不会见去掉)你可以当某某平等层楼扔下水球来测试,如果水球没清除,你得还捡起来继续用。

输入

输入文件包含多组测试,每组测试为平履行。每组测试包含两只整数k和n,(1<=
k<=100使n是一个LL的整数(没错,这座建筑物的确颇高),最后一组k=0,n=0代表了。

输出

对每次测试,输出在最差劲情况下,测出水球破掉楼层的至少次数。如果他多于63糟,就输出“More
than 63 trials needed.”

样例数据

样例输入 样例输出

2 100
10 786599
4 786599
60 1844674407370955161
63 9223372036854775807
0 0

14
21
More than 63 trials needed.
61
63

 

 

 

 

 

 

解析

定义f[i][j]
表示被i独水球和j次实验机会,将问题转化为高能测试到几重合
虽然会发生转换方程:f[i][j]=f[i][j-1]+f[i-1][j-1]+1;
继同样片是说选择在第k层试第一次于,如果破坏破了,说明边界在脚的层中。所以说选的老k层,k最深应满足k<=f[i-1][j-1]+1;
因为要是确保一旦水球在第k重合破坏坏了,下面的所有层都好当尚产生i-1个圆球和j-1不善机会时测出来;
前一部分表示选择在k层试第一次等,但是球并没有摔坏。这个时段最高就当k层的基本功及,加上
还有i个球和j-1差会经常能又于上测几重合~即f[i][j-1];
故此综上两有些,f[i][j]尽特别就是等于f[i-1][j-1]+1+f[i][j-1];

Code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

long long f[110][65];

void init()
{
    memset(f,0,sizeof(f));
    for(int i=1;i<64;i++)
        for(int j=1;j<64;j++)
            f[i][j]=f[i][j-1]+1+f[i-1][j-1];
}

int main()
{
    init();
    int k;
    long long n;
    while(scanf("%d%lld",&k,&n)!=EOF)
    {
        if(k==0) 
            break;
        k=min(k, 63);
        bool ok=false;
        for(int i=0;i<=63;i++)
        {
            if(f[k][i]>=n)
            {
                printf("%d\n",i);
                ok=true;
                break;
            }
        }
        if(!ok) 
            printf("More than 63 trials needed.\n");
    }
    return 0;
}

[UVA 1336] Fixing the Great Wall

问题叙述

Ministry of
Monuments公司计划了GWARR机器人来收拾长城。而若的职责就是是形容一个先后来算修理的无比小花费。
咱俩拿长城当是一致长长的直线,那么我们就算足以经过一个整数(某平等接触交长城同等端的离开)来叙述长城上一点之位置。GWARR机器人被放于长城及之某个一个地方又可望星星只方向匀速运动。计算着忽视修理过程的年华耗费。

输入

输入文件包含多组测试数据。
于各级一样组数:第1执行包含三单整数:n
(1<=n<=1000),表示长城达标要修补的地方;v
(1<=v<=100),表示机器人之单位速度;x
(1<=x<=500000),表示GWARR的早期位置。接下来的n行描述每一个破口的音讯,每一样实施包含三独整数:xi
(1<=xi<=500000),表示缺口的职;ci
(0<=ci<=50000),现在(也不怕是0时刻)修好这个缺口所欲的花;Δ
(1<=Δ<=50000),表示每一个单位时多的消费。因此,如果在t个单位时晚整治一个豁口,那么花费就是
c+t*Δ 。
输入数据保证:不设有个别独缺口位置重叠的状;机器人之发端位置不见面暨另外一个豁口位置重合。
当n=v=x=0时,输入文件截止。

输出

于各级一样组数,输出最小花费。题目保证最好小花费的值未见面超越1000000000。

样例数据

样例输入 样例输出

3 1 1000
1010 0 100
998 0 300
996 0 3
3 1 1000
1010 0 100
998 0 3
996 0 3
0 0 0

2084
1138

 

 

 

 

 

 

 

 

解析

如果惦记最后代价最低,就非可知蹦着修复,也不怕是通过一段时间后既修复好的烂应是均等段落连接区间。定义dp(i,j,k)表示修好(i,j)后机器人停留于k(0表示于左端,1象征以右端)端的费用。修复某处破损的代价虽然非是定值,但也是就时间线性增长之,所以当修复完毕一地处或同一段破损时,修复外破损的花销可算出来,只需要以那个增长到眼前状态即可,也足以作为修复某处破损产生的时间代价。状态转移方程:dp(i,j,1)=min(dp(i,j-1,0)+w1,dp(i,j-1,1)+w2) ;dp(i,j,0)=min(dp(i+1,j,0)+w3,dp(i+1,j,1)+w4)
其中,w1、w2、w3、w4也对应产生的年月代价和修复代价的同。

Code

 

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=1005;
const double inf=1e30;

struct node
{
    int x,c,dlt;
};
node p[N];

int n,v,x;
double dp[N][N][2],s[N];

bool cmp(node a,node b)
{
    return a.x<b.x;
}

double dfs(int l,int r,int k)
{
    if(dp[l][r][k]>-1.0)
        return dp[l][r][k];
    if(l==r)
    {
        double t=fabs((double)x-(double)p[l].x)/(double)v;
        dp[l][r][k]=s[n]*t+p[l].c;
        return dp[l][r][k];
    }
    if(k==0)
    {
        double a=dfs(l+1,r,0);
        double b=dfs(l+1,r,1);
        double t1=(double)(p[l+1].x-p[l].x)/(double)v;
        double t2=(double)(p[r].x-p[l].x)/(double)v;
        double d=s[l]+s[n]-s[r];
        dp[l][r][k]=min(a+d*t1,b+d*t2)+(double)p[l].c;
    }
    else
    {
        double a=dfs(l,r-1,0);
        double b=dfs(l,r-1,1);
        double t1=(double)(p[r].x-p[l].x)/(double)v;
        double t2=(double)(p[r].x-p[r-1].x)/(double)v;
        double d=s[l-1]+s[n]-s[r-1];
        dp[l][r][k]=min(a+d*t1,b+d*t2)+p[r].c;
    }
    return dp[l][r][k];
}

int main()
{
    while(~scanf("%d%d%d",&n,&v,&x))
    {
        if(n+v+x==0)
            break;
        for(int i=1;i<=n;++i)
            scanf("%d%d%d",&p[i].x,&p[i].c,&p[i].dlt);
        sort(p+1,p+n+1,cmp);
        s[0]=0.0;
        for(int i=1;i<=n;++i)
            s[i]=s[i-1]+(double)p[i].dlt;
        memset(dp,-1.0,sizeof(dp));
        printf("%d\n",(int)min(dfs(1,n,0),dfs(1,n,1)));
    }
    return 0;
}

 

[UVA 12105] Bigger is Better

问题叙述

Bob有n根火柴。他好用火柴摆出0~9任意一个数字,如下图所示:

威尼斯人官网 7

如今,给有一个平头m,要求用非跳n根火柴摆一个尽可能大之整数。

输入

输入文件包含多组测试数据。每一样组数占一推行,包含两独整数n
(n<=100)和m (m<=3000),其意义见题目叙述。
输入文件为一个单身的’0’结束。

 

输出

对每一样组数,输出计算产生的答案;若无脱,则输出-1。注意仍样例所受出的格式输出。

样例数据

样例输入 样例输出

6 3
5 6
0

Case 1: 111
Case 2: -1

 

 

 

 

解析

<参考了 dawxy 大神的笔触>

可以用dp[i][j]代表除以m余j的i位数最少要多少火柴这个状态计算,转移方程是:用dp[i][j]+c[k]来更新dp[i+1][(j*10+k)%m](c[]大凡每个数字要花费的火柴数量,k是当前枚举的数字)。可以避大精度提高效率,但是怎么规定各一样个上之数字还是啊也,需要为此dp[i][0]找到最老之i使得dp[i][0]不是INF(初始化dp[][]啊INF),这样尽管得确定这极度可怜数字有几乎号了(位数多的早晚比各类数少之坏),然后于算各国一样个上最充分可以是什么数字,从深至有些枚举每一样号上之数字,第一单让sum+dp[i-1][s]+c[j]<=n的数字就是该位上的无限可怜价值(其中s是去丢就无异各类上之数字剩下的几乎各的余数为s时让这总的数字会让m整除)。
依照,m=7,并且都知道即数字个数也3,首先试着为高位为9,如果得以摆放来9ab这样的整数,那么早晚是极其特别的,那么哪些确定是否摆起9ab吧?因为900%7=4,所以s,就是后少号’ab’%7当等3,(这里具体怎么竟的下边再说),如果dp[2][3]+c[9]+sum<=n,(sum是就规定的高位的数字之总花费),就证明火柴数量足够摆有9ab,否则最高位就不是9待连续搜寻,如果可以摆有那么还是历程直到算出每一样员上的数字。还可以先处理计算出每个x00..这样数字%m的值用y数组保存,其实还是采用了一些强精度计算–大数取余。

现行虽独自来一个题材了,怎样算出s,就是曾经掌握即整数为7ab%m
= 0和700%m,求出ab%m的价,我算了几乎单数字,找来了一个原理:
脚几乎员之余数s等于
m-当前即刻同号之数字x00..%m的值-v(前面有都规定的x00..%m之和)
据:假设最充分数字23450,m=7
20000%7=1,3000%7=4,400%7=1,50%7=1,0%7=0
2确定时
s(后4位%7)=(7-1-0)%7=6;v=0+1 验证:3450%7=6
23确定时
s(后3位%7)=(7-4-1)%7=2;v=1+4 验证:450%7=2
234确定时
s(后2位%7)=(7-1-5)%7=1;v=1+4+1 验证:50%7=1
2345确定时
s(后1位%7)=(7-1-6)%7=0;v=1+4+1+1 验证:0%7=0
需留意一下v可能超过m,所以测算v时需要模m。计算s时或者啊负数,需要先加m再模m

Code

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

#define MAXM 3010
#define MAXN 105
#define MAXW 55
#define INF 0x3f3f3f3f

const int c[10]={6,2,5,5,4,5,6,3,7,6};
int dp[MAXW][MAXM],y[10][MAXW][MAXM],ans[MAXW],sw,n,m;

void sloved()
{
    memset(ans,-1,sizeof(ans));
    int sum=0,v=0;
    for(int i=sw;i>=1;i--)
    {
        for(int j=9;j>=0;j--)
        {
            if(sum+dp[i-1][(m-y[j][i-1][m]-v+m)%m]+c[j]<=n)
            {
                ans[i]=j;
                sum+=c[j];
                v=(v+y[j][i-1][m])%m;
                break;
            }
        }
        if(-1==ans[i])
        {
            if(n>=6)
                puts("0");
            else
                puts("-1");
            return;
        }
    }
    for(int i=sw;i>=1;i--)
        printf("%d",ans[i]);
    puts("");
}

int main()
{
    int Count=0;
    for(int i=1;i<=9;i++)
    {
        for(int k=1;k<=3000;k++)
        {
            int s=i;
            y[i][0][k]=i%k;
            for(int j=1;j<=50;j++)
            {
                s=s*10%k;
                y[i][j][k]=s;
            }
        }
    }
    while(~scanf("%d%*c",&n)&&n)
    {
        scanf("%d%*c",&m);
        memset(dp,0x3f,sizeof(dp));
        dp[0][0]=0;
        int w=n>>1;
        for(int i=0;i<w;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(INF==dp[i][j])
                    continue;
                for(int k=0;k<=9;k++)
                {
                    if(dp[i][j]+c[k]<=n)
                        dp[i+1][(j*10+k)%m]=min(dp[i+1][(j*10+k)%m],dp[i][j]+c[k]);
                }
            }
        }
        sw=-1;
        for(int i=w;i>=1;i--)
        {
            if(INF!=dp[i][0])
            {
                sw=i;
                break;
            }
        }
        printf("Case %d: ",++Count);
        if(-1==sw)
            puts("-1");
        else
            sloved();
    }
    return 0;
}

[UVA 10618 | UVA 1204] Fun Game

问题叙述

差一点个子女在相同株老树旁占成一圈玩玩。由于树生老,每个孩子只能看见离他靠近之丁。
夫玩由许多轮子组成。在玩乐之启幕,一个任意的儿童会得到一致摆放张,如果是孩子是男孩,会于纸上勾画一个’B’;如果是女孩,会于纸上勾画一个’G’。然后他随意选择一个样子(顺时针或逆时针),将纸递给当这势头直达跟外相邻的人数,新的人头呢会于张上勾画下团结之性,继续用纸递给其他一个口(按照以前的方向)……就这么,这张纸从一个儿女到至其它一个孩子手中,直到一个男女宣布游戏结束。
推选个例,假设发生5个男女用培育围起来,如Figure
1,。现在,若纸从Kid1起来往逆时针走,在Kid3已下,那么我们不怕会见于张上获取一个字符串”BBG”。
当N轮游戏后,我们会拿走N张写起’B’和/或’G’的字符串的白纸。一个孩子会赢得有的这些纸,并且要算是有最少有略个儿童与了玩。我们知晓当自由情况下,至少发生个别个小。写一个程序,计算这最少之丁。

威尼斯人官网 8

输入

输入文件包含多组测试数据。
于各一样组数据:第1实行包含一个整数N
(2<=N<=16),表示总共发生N个字符串;接下的N行,每行包含一个由于’B’和/或’G’组成的字符串,字符串的尺寸都不越100。
当N=0时,输入数据了。

输出

于各一样组数据,输出可能的最少的儿女往往。

样例数据

样例输入 样例输出

3
BGGB
BGBGG
GGGBGB
2
BGGGBBBGG
GBBBG
0

9
6

 

 

 

 

 

 

 

 

解析

咱俩可以以预处理时拿富有相互包含的字符串合并,然后f[i][j][k]
表示手上字符串已经包含的字符串为i,并且为j结尾且该可行性为k的最小价,然后每次枚举转移,注意最后一个字符串要处理一下它们跟率先单字符串的公家部分(因为是绕),然后可能产生一个字符饶了一点圈这种情况,这时我们最终必将得管具有字符合并变成极丰富之那么一个,然后据此kmp求下其的顶小循环节输出就实行了,注意有所答案都使和2取最好要命价值。

Code

#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>

using namespace std;

int n,ans,tot_length;
int dis[17][17][2][2],f[1<<16][17][2];
bool Mask[17];

struct String
{
    char y[105];
}s[17],Rs[17],S[17];

bool cmp(String a,String b)
{
    if(strcmp(a.y,b.y)>0)
        return true;
    return false;
}

void Get_re(String s[])
{
    for(int i=1;i<=n;i++)
    {
        int l=strlen(s[i].y);
        for(int j=0;j<l;j++)
         Rs[i].y[l-j-1]=s[i].y[j];
        Rs[i].y[l]='\0';
    }
}

int got_val(char a[],char b[])
{
    int l1=strlen(a),cnt;
    for(int i=0;i<l1;i++)
    {
        bool flag=true;
        cnt=0;
        for(int j=i;j<l1;j++)
            flag&=(a[j]==b[cnt++]);
        if(flag)
            return cnt;
    }
    return 0;
}

void Init()
{
    int cnt=0;
    memset(Mask,0,sizeof(Mask));
    Get_re(s);
    for(int i=1;i<=n;i++)
    {
        if(strcmp(Rs[i].y,s[i].y)>0)
            S[i]=Rs[i];
        else
            S[i]=s[i];
    }
    sort(S+1,S+1+n,cmp);
    for(int i=1;i<=n;i++)
        if(strcmp(S[i].y,S[i-1].y))
            S[++cnt]=S[i];
    n=cnt;
    Get_re(S);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i!=j)
                if(strstr(S[j].y,S[i].y)!=NULL||strstr(S[j].y,Rs[i].y)!=NULL)
                    Mask[i]=true;
    cnt=0;
    for(int i=1;i<=n;i++)
        if(!Mask[i])
            S[++cnt]=S[i];
    n=cnt;
    Get_re(S);
    tot_length=0;
    for(int i=1;i<=n;i++)
        tot_length+=strlen(S[i].y);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i!=j)
            {
                dis[i][j][0][0]=got_val(S[i].y,S[j].y);
                dis[i][j][0][1]=got_val(S[i].y,Rs[j].y);
                dis[i][j][1][0]=got_val(Rs[i].y,S[j].y);
                dis[i][j][1][1]=got_val(Rs[i].y,Rs[j].y);
            }
    ans=0;
    memset(f,-1,sizeof(f));
}

int kmp()
{
    int Next[18],l=strlen(S[1].y);
    memset(Next,0,sizeof(Next));
    int now=Next[0]=-1;
    for(int i=1;i<l;i++)
    {
        while(now>=0&&S[1].y[now+1]!=S[1].y[i])
            now=Next[now];
        if(S[1].y[now+1]==S[1].y[i])
            now++;
        Next[i]=now;
    }
    return l-1-Next[l-1];
}

int main()
{
    while(scanf("%d",&n)&&n)
    {
        for(int i=1;i<=n;i++)
            scanf("%s",s[i].y);
        Init();
        if(n==1)
        {
            ans=kmp();
            cout<<max(ans,2)<<endl;
            continue;
        }
        f[1][1][0]=0;
        int tot=(1<<n)-1;
        for(int i=0;i<tot;i++)
            for(int j=1;j<=n;j++)
                if((1<<(j-1))&i)
                    for(int re=0;re<2;re++)
                        if(f[i][j][re]>=0)
                        {
                            for(int k=1;k<=n;k++)
                                if(!(i&(1<<(k-1))))
                                {
                                    int sta=i+(1<<(k-1));
                                    if(sta!=tot)
                                    {
                                        f[sta][k][0]=max(f[sta][k][0],f[i][j][re]+dis[j][k][re][0]);
                                        f[sta][k][1]=max(f[sta][k][1],f[i][j][re]+dis[j][k][re][1]);
                                    }
                                    else
                                    {
                                        f[sta][k][0]=max(f[sta][k][0],f[i][j][re]+dis[j][k][re][0]+dis[k][1][0][0]);
                                        f[sta][k][1]=max(f[sta][k][1],f[i][j][re]+dis[j][k][re][1]+dis[k][1][1][0]);
                                        ans=max(ans,f[sta][k][0]);
                                        ans=max(ans,f[sta][k][1]);
                                    }
                                }
                        }
        cout<<max(tot_length-ans,2)<<endl;
    }
    return 0;
}

[UVA 12099] Bookcase

题材叙述

有N本书,每本书有一个冲天Hi和宽度Wi。现在若构建一个叔叠的书架,你可选取将n本书放在书架的啊一样交汇。设三重叠高度(该层书之顶充分惊人)之同为h,书架总宽(即各级层总增长率的绝老价值)为w,则要求h*w尽量小。

输入

输入文件包含多组数。测试数据的组数T会在输入文件的率先推行让闹(1<=T<=20)。
对于每一样组数据:第1尽包含一个正好整数N
(3<=N<=70),表示开的多少。接下来的N行每行包含两独刚刚整数Hi和Wi
(150<=Hi<=300,5<=Wi<=30),分别代表第i本书的冲天与宽窄。题目中为有底长度都因毫米(mm)为单位。

输出

对此各一样组数,输出能盛所有书的动静下,书架的h*w的太小价。

样例数据

样例输入 样例输出

2
4
220 29
195 20
200 9
180 30
6
256 20
255 30
254 15
253 20
252 15
251 9

18000
29796

 

 

 

 

 

 

 

 

 

 

 

解析

主题采用了DP+加状态剪枝的国策;
率先须明白:前面i本书的特等放法是出于前i-1本书的极品艺术的根底及助长第i本书组合要来;
d[i][j][k]意味着都安排前i本书,第二重合宽度为j,第三交汇宽度为k,且第二重叠的可观过等于第三层的冲天,最高的那本书在第一交汇时之
第二重叠与老三叠的极小高度和;
拖欠状态是当各个层厚度一定情况下之极度优解;这样一来最终解要遍历i=n的所有状态求最好良好;由于d[i][j][k]连无能够强烈的找来该所据的分段结构,但因故它来更新i+1的状态也比较容易转换,所以使用刷表法
再有状态太好,需要剪枝。

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

#define INF 2110000
#define Inf 1000

const int maxn=71;
const int maxm=2105;

int d[maxn][maxm][maxm],n,maxw=30,sumw[maxn];

struct Book
{
    int H,W;
}a[maxn];

bool cmp(Book a,Book b)
{
    return a.H>b.H;
}

int f(int i,int j)
{
    return i==0 ? j : 0;
}
long long dp()
{
    int lim=n*maxw;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=lim;j++)
            for(int k=0;k<=lim;k++)
            {
                if(j+k>sumw[i]-a[1].W||sumw[i]-j-k+30<j||j+30<k)
                break;
                    d[i][j][k]=Inf;
            }
    d[1][0][0]=0;
    int ans=INF;
    for(int i=1;i<n;i++)
        for(int j=0;j<=lim;j++)
            for(int k=0;k<=lim;k++)
            {
                if(j+k>sumw[i]-a[1].W||sumw[i]-j-k+30<j||j+30<k)
                    break;
                d[i+1][j][k]=min(d[i+1][j][k],d[i][j][k]);
                d[i+1][j+a[i+1].W][k]=min(d[i+1][j+a[i+1].W][k],d[i][j][k]+f(j,a[i+1].H));
                if(j>0)
                    d[i+1][j][k+a[i+1].W]=min(d[i+1][j][k+a[i+1].W],d[i][j][k]+f(k,a[i+1].H));
            }
    for(int j=0;j<=lim;j++)
        for(int k=0;k<=lim;k++)
        {
            if(j+k>sumw[n]-a[1].W||sumw[n]-j-k+30<j||j+30<k)
                break;
            if(d[n][j][k]!=INF&&j>0&&k>0)
                ans=min(ans,(d[n][j][k]+a[1].H)*(max(sumw[n]-j-k,max(j,k))));

        }
    return ans;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d %d",&a[i].H,&a[i].W);
        sort(a+1,a+1+n,cmp);
        sumw[0]=0;
        for(int i=1;i<=n;i++)
            sumw[i]=a[i].W+sumw[i-1];
        printf("%I64d\n",dp());
   }
   return 0;
}

CQBZOJ上的 动态规划作业

拖欠演习包含了以下问题,这些题目都只是当威尼斯人官网 9上找到,在此处仅仅让有问题叙述:

1510 Problem A 遇见

<Vijos
1280>

燕姿在桥底当即无异于端,而xx在桥的外一样端。这座大桥非常特殊,桥面是由于2N-1只方格组成的,每个方格里写来一个数码Ai(-50<=Ai<=50)。如下是N=4时之事态。可以当燕姿由不过下面出发。每一样破,她得以提高跳到同团结所于方格相临的中一个方格内(例如在极端下的7蒙受,可以超过到齐一行的10跟8中)。当燕姿跳到最好上方的方格后,她就非克再倒了。(在匪到上前,不允许超过到说明格外。)每于一格内,都设拿格内的数字写下去。
但是,仅仅到达顶端是不够的。桥会向彼岸的xx询问一个数字k,燕姿到达顶端后,拿出写下来的数字,可以当随意两个数字中长“+”或“-”号,使得计算的结果m最接近k。经过大桥的判定,如果对大桥上的方格m是极致接近k的数字,那么燕姿尽管足以经过桥和xx相遇,否则………
(为了给燕姿能重易于地通过,xx给出之数字总是0)你的任务,就是拉燕姿搜来此极端接近k的m.

1511 Problem B 火车票

<Vijos
1292>

一个铁路线上有n(2<=n<=10000)个火车站,每个火车站到该路线的首发火车站距还是一度了解之。任意两站内的票价如下表所示:站之间的相距
X与票价的关联:如果离开 :0 < X < =L1 则票价也C1 如果距离 :L1
< X < =L2 则票价也C2 如果距离 :L2 < X < =L3 则票价为C3
其中L1,L2,L3,C1,C2,C3都是曾经知道之正整数,且(1 <= L1 < L2 <
L3 <= 10^9, 1 <= C1 < C2 < C3 <=
10^9)。显然要两立内的相距超过L3,那么由平站到另外一样立至少要购置简单摆放票。注意:每一样布置票以运用时只好从平站起来至另外一样立结束。现在亟需你对此给定的路线,求来由该线路及之站A到站B的不过少票价。你可知到位为?

1512 Problem C 晴天小猪历险记

<Vijos
1006>

于怪长远很久以前,有一个动物村庄,那里是猪的世外桃源(^_^),村民们努力、勇敢、善良、团结……
不了起同龙,最小之矮小猪生病了,而这种病是不过罕见的,因此大家还尚未储存这种药品。所以晴天小猪从告奋勇,要错过行使这种药草。于是,晴天小猪的传奇故事就通过展开……
这同一上,他到了一样栋山的山脚下,因为只有这所山中的相同个隐者才知道这种药草的大街小巷。但是上山的路途错综复杂,由于微小猪的病情,晴天小猪想寻找一修需经常不过少之路到达山顶,但本其一头雾水,所以向你求助。
山因而一个三角形表示,从山头依次为下发生1段落、2段、3段等山路,每一样截用一个数字T(1<=T<=100)表示,代表晴天小猪在及时无异于段子山路上需要爬的年华,每一样糟糕她还足以往左、右、左上、右上季单方向动(**注意**:在肆意一交汇的第一截也得移动及本层的结尾一段落要上一样层的最后一截)。
晴天小猪从山的左下角出发,目的地也巅峰,即隐者的斗室。

1514 Problem D 添加括号

<Vijos
1038>

于一定一个正整数序列a(1),a(2),…,a(n),(1<=n<=20)
不改动序列中每个元素于班中之位置,把它相加,并用括号记每次加法所得的跟,称为中与。
例如: 给有队是4,1,2,3。 第一栽添括号方式:
((4+1)+(2+3))=((5)+(5))=(10)
有三只中等及凡5,5,10,它们的与也:5+5+10=20 第二种添括号方法
(4+((1+2)+3))=(4+((3)+3))=(4+(6))=(10)
中间及凡3,6,10,它们的同为19。现在只要增补上n-1对括号,加法运算依括号顺序进行,得到n-1独中等及,求出而中和之同最小之添括号方式。

1515 Problem E 盖房子

<Vijos
1057>

恒の灵魂最近得了面积为n*m的同一不胜块土地(高兴ING^_^),他惦记当这块土地及构筑一模一样所房屋,这个房屋要是刚方形的。但是,这块土地永不十全十抖,上面有好多无平易的地方(也可以吃瑕疵)。这些弱点十分恶心,以至于根本未可知当方盖一砖一瓦。他期待找到同样片最要命之正方形无瑕疵土地来以房屋。不过,这并无是呀难题,永恒の灵魂在10分钟内虽自在解决了此题目。现在,您也来试试看吧。
 

1516 Problem F 迎春舞会的三人口组舞(版本2)

<Vijos
1061>

HNSDFZ的同校等为了庆祝新年,准备排练一庙舞
n个人选择来3*m人,排成m组,每组3人。
站的队形——较矮的2独人口站两侧,最高的立中。
从对称学角度来玩,左右两独人口之身高更是接近,则马上无异组的“残疾程度”越低。
计算公式为 h=(a-b)^2 (a、b为于矮的2人的身高) 那么问题来了。
现在候选人有n个人,要于他们中选择产生3*m个人脱舞蹈,要求完全的“残疾程度”最低。

1517 Problem G 新年佳话之红包

<Vijos
1069>

xiaomengxian一进家,发现外公、外婆、叔叔、阿姨……都盖于厅里当正他吧。经过周密观察,xiaomengxian发现他们拥有人刚刚组成了一个凸多边形。最紧要的凡,他们每个人手里还将在一个红包(^o^)。于是充分着急,xiaomengxian决定找一长长的太差的途径,拿到具备的红包。
假使屋里共有N个人拿在红包,把她们分别从1暨N编号。其中,编号也1的总人口即使因为于大门口,xiaomengxian必须从此处出发去用任何的红包。一长长的官方的不二法门要通过所有的点同样涂鸦都仅一次等。
 

1518 Problem H 新年佳话之打牌

<Vijos
1071>

过年的时刻,大人们最好喜爱的移动,就是打牌了。xiaomengxian不见面打牌,只好为于另一方面看在。
这天,正当一浩大人数打牌打得生气勃勃的时候,突然有人喊叫道:“这符合牌少了几张!”众人一数,果然是遗失了。于是马上副牌的所有者得意地说:“这是同幅特制的牌子,我掌握整副牌每一样布置的重。只要我们遂一下剩余的牌子的总重量,就可知清楚少了如何牌子了。”大家都以为这办法对,于是称有剩下的牌的总重量,开始计少了什么样牌子。由于数据量比较充分,过了不久,大家都算是得晕头转向了。
这时,xiaomengxian大声说:“你们看本身之吧!”于是他以出笔记本电脑,编出了一个顺序,很快就管少的牌子找了下。
如果是你遇上了这么的状呢?你会办成同样的政工为?

1524 Problem I 小胖守皇宫

<Vijos
1144>

huyichen世子事件后,xuzhenyi成了空特聘的御前五星级侍卫。
皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的样;某些宫殿间可以互相望见。大内保卫森严,三步一哨卡,五步一哨,每个宫殿都设有人全天候守卫,在不同的皇宫安排看守所要的用不同。
可是xuzhenyi手上的经费不足,无论如何也无奈在每个宫殿都安排留守侍卫。
帮助xuzhenyi布置侍卫,在防御所有禁的前提下,使得花费的经费最少。

1525 Problem J 猫狗大战

<Vijos
1153>

新一年之猫狗大战通过SC(星际争霸)这款经典的游乐来比赛,野猫和飞狗这对准朋友为夫都准备好老了,为了使战争再次产生难度和巧合,双方约定只能挑Terran(人族)并且只能去机枪兵。比赛开始了,很快,野猫已经攒足几帮机枪兵,试探性的鼓动进攻;然而,飞狗的机枪兵个数也早就重重了。野猫和飞狗的兵器在飞狗的家门口相遇了,于是,便生同等街腥风血雨和阵阵惨叫声。由于是于飞狗的家门口,飞狗的枪杆子补充为会快,野猫看敌不过,决定撤军。这时飞狗的军力也相差够多,所以无追出去。由于未允造医生,机枪兵没道补血。受伤的兵只好忍了。555-。现在,野猫又存足了足够的兵力,决定发起第二不行攻击。为了使这次攻击让狗狗造成更可怜之打击,野猫决定将现有的军火分成两组成部分,从零星程进攻。由于来几兵在第一次于杀中受伤了,为了使个别局部的兵实力平均些,分的规则是如此的:1)两组成部分家伙之个数最多只能见仁见智一个;2)每有武器之血值总和要要硬着头皮接近。现在求您编一个先后,给定野猫现在有的兵之个数和每个兵之血格值,求出野猫按上述规则分成两有些后各有武器的血值总和。
 

1526 Problem K 分梨子

<Vijos
1157>

Finley家的庭院里发生棵梨树,最近到手了好多梨。于是,Finley决定挑来有梨,分给幼稚园的宝贝儿等。可是梨子大小味道还未极端一致,一定要是尽量挑选那些差不多的梨子分吃男女辈,那些分到小梨子的宝宝才不见面哭来。每个梨子都具备两独属于性值,Ai和Bi,本别表示梨子的分寸和甜度情况。假设以选出的梨中,两个属性之尽小价分别是A0和B0。只要对有给选出的梨子i,都满足C1*(Ai-A0)+C2*(Bi-B0)≤C3(其中,C1、C2和C3都是曾了解之常数),就好看这些梨子是相差不多的,可以用来划分被小们。那么,作为幼稚园园长的乃,能算是有极其多得择有些许个梨吗?

1527 Problem L 岳麓山上打水

<Vijos
1159>

今天天气好晴朗,处处好景观,好青山绿水!蝴蝶儿忙啊,蜜蜂为忙碌,信息组的同窗等尤其繁忙。最近,由于XX原因,大家不得不到岳麓山错过提水。55555555~,好累啊。  信息组有一个容量也q升的大缸,由于大家还特别自觉,不乐意浪费和,所以每次都见面刚好将缸盛满。但是,信息组并没有桶子(或者瓢)来舀水,作为组内的生存委员,你不能不肩负重任,到新一地道去选购桶子。新一了不起有p种桶子,每种桶子都发管根本多只^_^,且价格一样。由于大家还充分节省,所以若得尽量少打桶子。如果产生强方案,你必须挑选“更小”的那种方案,即:把及时有限单方案的集(不同尺寸的桶子组成)按升序排序,比较第一单桶,选择第一单桶容积较小之一个。如果第一个桶相同,比较第二个桶,也以上面的法子选择。否则继续这样的较,直到相较的鲜单桶不相同为止。例如,集合{3,5,7,三}
比集合 {3,6,7,8}
要好。为了拿缸装满水,大家可以预先由岳麓山之井里拿桶装满水提回来,然后倒进缸里。为了不怪难为或浪费宝贵的水资源,大家不要把缸里的水倒出来要将桶里的水倒掉,也无见面管桶里的度还倒回井中,(这样见面传染井水)。当然,一个桶可以下频繁。例如,用一个容积也
1 升的桶可以以随意容量的大缸装满水。而别的组成将麻烦来。

1528 Problem M 公路巡逻

<Vijos
1168>

于相同长没有分岔的高速公路及发出n个关口,相邻两个关口之间的去还是10km。所有车辆以即时条高速公路上之最低速度为60km/h,最高速度也120km/h,并且不得不于关口处改变速度。巡逻的法子是以有时刻Ti从第ni单关口派出同部巡逻车匀速驶抵第(ni+1)个关口,路上吃的时光啊ti秒。
两辆车相遇是依赖其之间时有发生超车或者少车以抵达某关口(同时出发不到底相遇)。
巡逻部门想明白相同辆被6点打点起第1个关口出发去第n单关口的车(称为目标车)最少会跟稍辆巡逻车相遇,请编程计算的。假设有车辆达关口的天天都是整秒。

1529 Problem N 核电站问题

<Vijos
1232>

一个核电站发生N个放核物质的坑,坑排列于平等漫长直线上。如果老是M个坑中放入核物质,则会发生爆炸,于是,在一些坑中恐不放核物质。
现在,请您算:对于给定的N和M,求无发生爆炸的放置核物质的方案总数(n
<= 50, m <= 5)

1530 Problem O 天堂之馈赠

<Vijos
1235>

小杉找到了开棉花糖的极致美妙方案,想去摘云朵,可是摔死了……
他过来了天堂。天堂当然是挺挺之,也是好凌乱的。小杉看同一块路标,写在“天堂之赠与”。考虑到稍微杉刚死没有多久,为了抚慰他叫创的心灵以及依依的情感,天堂派出一个天使给小杉送礼,但IQ不敷高的小杉可免克用到好礼。馈赠在西方门口进行。天使站于云端,往下丢礼物。天堂之法家的宽窄为W格(按1..W编号),高度也0格,云端的惊人为H格,小杉只能站于格子里。开始经常(第0秒),小杉站在西方的家的第P格。馈赠开始后,天使会于一些时刻从云端的某格扔礼物下来,礼物退的进度(格/秒)是无一致的。小杉左右走去搭礼物(每秒可以倒1格或者不走)。礼物中的价自然是未一致的,小杉事先知情了每个礼物的价值。当礼品在某个同秒末恰好到达小杉所在的格子中,小杉就收下了这礼物。小杉想知道,他最好多好用到价值为稍之人情。而且,由于礼盒退的速略可以挺……,小杉还想清楚凡是勿是来来人情他什么啊以不交。

 

 

Time:
2017-07-19