程序竞赛SDAU第六周的总结

先说下最近几周的大体情况吧 ,最近就是一直在学动态规划dp,花的时间也挺多的,说明这一部分也挺重要,也确实挺难的,首先是课件上的题,就算老师讲过了,感觉有一些题,自己仍然是掌握不住 ,就是感觉这个思路根本想不到,其次就是最近a-v的练习题上,这个真的是 首先全英,这个受不了,其次就是有一些题它,就是连dp【i】【j】 i j 表示什么都想不到,还有一些就是根本没有思路,就是不知道从哪里开始下手,还是剖析问题的能力不行。
下面写几个题,这些题都是自己会一部分,总是有一些细节没想到,或者给忽略了

FatMouse believes that the fatter a mouse is, the faster it runs. To disprove this, you want to take the data on a collection of mice and put as large a subset of this data as possible into a sequence so that the weights are increasing, but the speeds are decreasing.
Input
Input contains data for a bunch of mice, one mouse per line, terminated by end of file.

The data for a particular mouse will consist of a pair of integers: the first representing its size in grams and the second representing its speed in centimeters per second. Both integers are between 1 and 10000. The data in each test case will contain information for at most 1000 mice.

Two mice may have the same weight, the same speed, or even the same weight and speed.
Output
Your program should output a sequence of lines of data; the first line should contain a number n; the remaining n lines should each contain a single positive integer (each one representing a mouse). If these n integers are m[1], m[2],…, m[n] then it must be the case that

W[m[1]] < W[m[2]] < … < W[m[n]]

and

S[m[1]] > S[m[2]] > … > S[m[n]]

In order for the answer to be correct, n should be as large as possible.
All inequalities are strict: weights must be strictly increasing, and speeds must be strictly decreasing. There may be many correct outputs for a given input, your program only needs to find one.
Sample Input
6008 1300
6000 2100
500 2000
1000 4000
1100 3000
6000 2000
8000 1400
6000 1200
2000 1900
Sample Output
4
4
5
9
7
思路:这个题其实就是求最长系列的问题 这个题问题出在哪里呢,就是在求最长不下降序列的时候,这个我问题好求长度,就是我 不知道如何输出这一串序列,当时懵逼了,看的本子上的做法是这样,但自己不理解然后我又去看了学长求最长不下降虚列的方法

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
struct p
{
	int m, v, x;
}a[1002];
int h[1002][1002];
int cmp(p a, p b)
{if(a.m!=b.m)
	return a.m<b.m;
return a.v>b.v;
}
int xx[10001];
int main() 
{
	int i = 1; int n=0;
	while (cin>>a[i].m>>a[i].v)
	{
		n = i;
		a[i].x = i;
		h[i][2] = 1; h[i][3] = 0;
		i++;
	}
	sort(a+1, a+n+1, cmp);
	int l, k;
	for (int i = n-1; i >=1; i--)
	{
		 l = 0;k = 0;
		for (int j = i + 1; j <=n; j++)
			if (a[j].v<a[i].v&&h[j][2]>l&&a[j].m!=a[i].m)
			{
				l = h[j][2];
				k = j;
			}
		if (l > 0)
		{
			h[i][2] = l + 1; h[i][3] = k;
		}
	}
	k = 1;
	for (int j = 1; j<=n; j++)
		if (h[j][2]>h[k][2]) k = j;
	cout << h[k][2] << endl;
	while (k!= 0)
	{
		cout << a[k].x<<endl; k = h[k][3];
	}
}

求最长不下降序列的 成员
其实也不是很难 那些成员都有一个特点,就是长度在到达这个成员的时候,长度都会加1 所以 你只要去遍历一遍,只要是那个c变了的地方就是成员 输出它就行了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 1001
#define MOD 2520
#define E 1e-12
using namespace std;
int a[N],f[N],c[N];
int main()
{
    int n;
    int maxx=-INF;
 
 
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
 
    int k;
    for(int i=1;i<=n;i++)
    {
        f[i]=1;
        for(int j=1;j<i;j++)
            if(a[j]<=a[i]&&f[j]+1>f[i])
                f[i]=f[j]+1;
        if(f[i]>maxx)
        {
            maxx=f[i];
            k=i;
        }
    }
    int q=0,m=maxx,i=k-1;
    c[q++]=k;
    while(m>1)
    {
        if(f[i]==m-1&&a[i]<=a[k])
        {
            c[q++]=i;
            k=i;
            m--;
        }
        i--;
    }
 
    printf("max=%d\n",maxx);
    for(i=q-1;i>=0;i--)
        printf("%d ",a[c[i]]);
 
    return 0;
}

Given a permutation a1, a2, … aN of {1, 2, …, N}, we define its E-value as the amount of elements where ai > i. For example, the E-value of permutation {1, 3, 2, 4} is 1, while the E-value of {4, 3, 2, 1} is 2. You are requested to find how many permutations of {1, 2, …, N} whose E-value is exactly k.
Input
There are several test cases, and one line for each case, which contains two integers, N and k. (1 <= N <= 1000, 0 <= k <= N).
Output
Output one line for each case. For the answer may be quite huge, you need to output the answer module 1,000,000,007.
Sample Input
3 0
3 1
Sample Output
1
4

Hint
There is only one permutation with E-value 0: {1,2,3}, and there are four permutations with E-value 1: {1,3,2}, {2,1,3}, {3,1,2}, {3,2,1}

思路:先去分析dp[i][j] i j 分别表示什么 i是表示到几 j是表示E
这个题是找的规律 先去想一下 dp【i】【j】跟谁有关 肯定跟 [i-1][j-1]
[i][j-1] 第一因为 长度为i 的 E为j 他不就是比【i-1】【j-1】的时候多了给i 这个i 可以去 跟那些不得分的去换对吧!所以 它能有多少种 办法 i-j个 可以交换
第二再去看 【i-1】【j】的情况 说明这个j不会多加分的 前面都是符合题意的 但是如果他换了也没什么影响呀 所以情况有 j+1中情况
所以得到dp公式

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iomanip>
using namespace std;
long long dp[1001][1001];
int main()
{
	for (int i = 1; i <= 1000; i++)
	{
		dp[i][0] = 1;
		for (int j = 1; j < i; j++)
		{
			dp[i][j] = (dp[i - 1][j - 1]*((i-j))+ dp[i - 1][j]*(j+1))%1000000007;
		}
	}
	int n, m;
	while (cin >> n >> m)
	{
		cout << dp[n][m] << endl;;
	}
}

自从见识了平安夜苹果的涨价后,Lele就在他家门口水平种了一排苹果树,共有N棵。

突然Lele发现在左起第P棵树上(从1开始计数)有一条毛毛虫。为了看到毛毛虫变蝴蝶的过程,Lele在苹果树旁观察了很久。虽然没有看到蝴蝶,但Lele发现了一个规律:每过1分钟,毛毛虫会随机从一棵树爬到相邻的一棵树上。

比如刚开始毛毛虫在第2棵树上,过1分钟后,毛毛虫可能会在第1棵树上或者第3棵树上。如果刚开始时毛毛虫在第1棵树上,过1分钟以后,毛毛虫一定会在第2棵树上。

现在告诉你苹果树的数目N,以及毛毛刚开始所在的位置P,请问,在M分钟后,毛毛虫到达第T棵树,一共有多少种行走方案数。
Input
本题目包含多组测试,请处理到文件结束(EOF)。
每组测试占一行,包括四个正整数N,P,M,T(含义见题目描述,0<N,P,M,T<100)
Output
对于每组数据,在一行里输出一共的方案数。
题目数据保证答案小于10^9
Sample Input
3 2 4 2
3 2 3 2
Sample Output
4
0

Hint
第一组测试中有以下四种走法:
2->1->2->1->2
2->1->2->3->2
2->3->2->1->2
2->3->2->3->2

思路:这个题的问题出来的特别搞笑 我想不到 dp 【i】【j】 ij去表示什么

真是没好好看题 i表示分钟 j用来表示到了那棵树了
dp关系式不难写 就是跟上一分钟 左右两棵树有关系
有个小问题就是初始化两头的问题 这两棵树吧 他们只能抄一个方向走
所以初始化 dp[0][p]=1 第零分钟的时候 在这个数的先走路径只有yi
在第一棵树时,只能由上一分钟的右边的树(第2棵)的状态转移而来,即dp[i][1]+=dp[i-1][2];
在第最后一棵树(第n棵)时,只能由上一分钟的左边的树(第n-1棵)的状态转移而来,即dp[i][n]+=dp[i-1][n-1];
而在中间的树的状态则有左右两边的状态决定。即dp[i][j]+=dp[i-1][j-1]+dp[i-1][j+1];

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iomanip>
using namespace std;
int dp[105][105];
int main()
{
	int n, p, m, t;
	while (cin >> n >> p >> m >> t)
	{
		memset(dp, 0, sizeof dp);
		dp[0][p] = 1;
		for (int i=1; i <=m; i++)
			for (int j = 1; j <= n; j++)
			{
				dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j + 1];
			}
		cout << dp[m][t] << endl;

	}


}

或者

#include<stdio.h>
#include<string.h>
int dp[110][110];
int max(int a,int b)
{return a>b?a:b;}
int main()
{
    int i,j,n,m,p,t;
    while(scanf("%d%d%d%d",&n,&p,&m,&t)!=EOF)
    {
       memset(dp,0,sizeof(dp));
       dp[0][p]=1;
       for(i=1;i<=m;i++)
       for(j=1;j<=n;j++)
       {
          if(j==1)
          dp[i][j]+=dp[i-1][j+1];
          else
          if(j==n)
          dp[i][j]+=dp[i-1][j-1];
          else
          dp[i][j]+=dp[i-1][j-1]+dp[i-1][j+1];
       }
       printf("%d\n",dp[m][t]);
    }
    return 0;
    }

Something happened in Uzhlyandia again… There are riots on the streets… Famous Uzhlyandian superheroes Shean the Sheep and Stas the Giraffe were called in order to save the situation. Upon the arriving, they found that citizens are worried about maximum values of the Main Uzhlyandian Function f, which is defined as follows:
在这里插入图片描述
In the above formula, 1 ≤ l < r ≤ n must hold, where n is the size of the Main Uzhlyandian Array a, and |x| means absolute value of x. But the heroes skipped their math lessons in school, so they asked you for help. Help them calculate the maximum value of f among all possible values of l and r for the given array a.

Input
The first line contains single integer n (2 ≤ n ≤ 105) — the size of the array a.

The second line contains n integers a1, a2, …, an (-109 ≤ ai ≤ 109) — the array elements.

Output
Print the only integer — the maximum value of f.

Examples
Input
5
1 4 2 3 1
Output
3
Input
4
1 5 4 7
Output
6
Note
In the first sample case, the optimal value of f is reached on intervals [1, 2] and [2, 5].

In the second case maximal value of f is reachable only on the whole array.
思路:这个题老师上课的时候提前给讲了,感觉老师不讲我可能想不到这样去做 嘻嘻
你看它正负跟i有关,无非就两种。而且它要求的是 做完差之后的序列 所以你再去找两个序列来做
然后去求两个大字段和。去比较然后输出最大的一个就可以了 主要是剖析题意,只要能把前边分析出来就行

#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iomanip>
using namespace std;
long long z[100005];
long long f[100005];
long long a[100005];
int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	for (int i = 1; i < n; i++)
	{
		if(i%2==0)
		{
			z[i] = abs(a[i] - a[i + 1]);
			f[i] = -z[i];
		}
		else
		{
			z[i] = -abs(a[i] - a[i + 1]);
			f[i] = -z[i];
		}
	}
	long long s = 0, max1= 0;;
	for (int i = 1; i <= n; i++)
	{
		if (s > 0)
			s += z[i];
		else s = z[i];
		max1 = max1 > s ? max1 : s;
	}
	long long ss=0,max2=0;
	for (int i = 1; i <= n; i++)
	{
		if (ss > 0)
			ss += f[i];
		else ss = f[i];
		max2 = max2> ss? max2 : ss;
	}
	if (max1 > max2) cout << max1 << endl;
	else cout << max2 << endl;
	
}

这是一个简单的生存游戏,你控制一个机器人从一个棋盘的起始点(1,1)走到棋盘的终点(n,m)。游戏的规则描述如下:
1.机器人一开始在棋盘的起始点并有起始点所标有的能量。
2.机器人只能向右或者向下走,并且每走一步消耗一单位能量。
3.机器人不能在原地停留。
4.当机器人选择了一条可行路径后,当他走到这条路径的终点时,他将只有终点所标记的能量。
在这里插入图片描述
如上图,机器人一开始在(1,1)点,并拥有4单位能量,蓝色方块表示他所能到达的点,如果他在这次路径选择中选择的终点是(2,4)

点,当他到达(2,4)点时将拥有1单位的能量,并开始下一次路径选择,直到到达(6,6)点。
我们的问题是机器人有多少种方式从起点走到终点。这可能是一个很大的数,输出的结果对10000取模。
Input
第一行输入一个整数T,表示数据的组数。
对于每一组数据第一行输入两个整数n,m(1 <= n,m <= 100)。表示棋盘的大小。接下来输入n行,每行m个整数e(0 <= e < 20)。
Output
对于每一组数据输出方式总数对10000取模的结果.
Sample Input
1
6 6
4 5 6 6 4 3
2 2 3 1 7 2
1 1 4 6 2 7
5 8 4 3 9 5
7 6 6 2 1 5
3 1 1 3 7 2
Sample Output
3948
思路:这个题感觉就是类似搜索dfs的做法
我刚开始拿到题 我就在想我从终点往回看 因为终点的是确定的 就是1 然后去看其他的 依次一直到起点,但我总是被 能量值给困住了,老是从那里想他不是能走好多步么 我还要再去写个for循环?然后考虑他其中的每一步有多少种 情况啊 这个思路其实差不多 但我应该按照搜索 从未知开始搜 搜到底就是已知。 然后 dp公式就 dp【x】【y】=dp[x][y]+dfs(x+i,y+j);就行了。然后我在其中出了很多的错误 就是如果dp=-1 的我return啥 ? 我没考虑到 还有 如果不等于 -1 就是说明这个 这个地方你搜完了 就直接return 就行了

#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iomanip>
long long dp[102][102];
long long a[102][102];
using namespace std;
int n, m;
int dfs(int x, int y)
{
	if (dp[x][y] != -1) return dp[x][y];
	else dp[x][y] = 0;
		for (int i = 0; i <= a[x][y]; i++)
		{
			for (int j = 0; j <= a[x][y]-i; j++)//消耗i个能量所能到达的格子的地方
			{
				if (x + i >= 1 && y + j >= 1 && x + i <= n && j + y <= m)
					dp[x][y] = (dp[x][y] + dfs(x+i, y + j)) % 10000;
			}
		}
		return dp[x][y];
}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		memset(dp, -1, sizeof dp);
		cin >> n >> m;
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
				cin >> a[i][j];
		dp[n][m] = 1;
		dfs(1,1);
		cout << dp[1][1] << endl;
	}
}

反思 :这几个题 是我在提交成功的基础上写出来的思路总结之类的东西 我剩下没做出来的 我会利用这两天的假期去查想办法搞明白 ,然后还有一点,对于老师讲的课件 我仍然有一部分没吸收好,虽然老师讲的挺好的,但我可能需要多花时间去做,在这一部分题 我刚开始的一个星期根本没放在心上 ,真的很惭愧 我会认真对待每一次的训练 跟好老师的步伐,虽然这部分挺难的 ,但我会多花时间跟上的

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值