错排问题
我们先来科普一下错排问题,oier们以后也会用到/
错排问题指考虑一个有 n个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排列的一个错排。 n个元素的错排数记为 D(n) 。 研究一个排列错排个数的问题,叫做错排问题或称为更列问题。 ---《百度百科》
看上去这就是一个递推问题,那么递推式是如何推出来呢? 当 n 个编号元素放在n个编号位置,元素编号与位置编号各不对应的方法数用 D(n) 表示,那么 D(n-1)就表示 n-1 个编号元素放在 n-1 个编号位置,各不对应的方法数,其它类推.
第一步,把第 n 个元素放在一个位置,比如位置 k ,一共有 n-1 种方法;
第二步,放编号为 k 的元素,这时有两种情况:⑴把它放到位置 n ,那么,对于剩下的 n−1 个元素,由于第 k 个元素放到了位置 n ,剩下 n−2 个元素就有 D(n−2) 种方法;⑵第 k 个元素不把它放到位置 n ,这时,对于这 n−1 个元素,有 D(n−1) 种方法;
综上得到
D(n) = (n-1) *(D(n-2) + D(n-1))
特殊地,D(1) = 0, D(2) = 1
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
int f[25],n;
int main()
{
scanf("%d",&n);
f[1]=0;f[2]=1;f[3]=2;
if(n==1||n==2||n==3)
{
printf("%d",f[n]);
return 0;
}
for(int i=4;i<=n;i++)
{
f[i]=(i-1)*(f[i-1]+f[i-2]);
}
printf("%d",f[n]);
return 0;
}
最短路径
#include <iostream>
#include <cmath>
using namespace std;
int n;
int a[205][205];
int f[205 * 205];
int main()
{
cin >> n;
int h = 98989898;
for (int i = 1; i < n; i++)
for (int j = i + 1; j <= n; j++)
{
cin >> a[i][j];
f[i] = h;
}
for (int i = n - 1; i >= 1; i--)
for (int j = i + 1; j <= n; j++)
{
f[i] = min(f[i], a[i][j] + f[j]);
}
cout << f[1] << "\n";
return 0;
}
用数组a[i][j]来存储从i到j的距离(用i->n表示)。
中转站1 | 中转站2 | 中转站3 | |
中转站1 | 0 | 5 | 15 |
中转站2 | 0 | 0 | 7 |
中转站3 | 0 | 0 | 0 |
dp[i]表示从i到终点的最短距离,(用i↑n表示)。
for (int i = n - 1; i >= 1; i--)
for (int j = i + 1; j <= n; j++)
f[i] = min(f[i], a[i][j] + f[j]);
以n=5为例
i | 4 | 3 | 2 | 1 |
比较内容 | 4↑5 | 3↑5 | 2↑5 | 1↑5 |
被比较内容 | 4->5,5↑5 | 3->4,4↑5 | 2->3,3↑5 | 1->2,2↑5 |
1->3,3↑5 | ||||
2->4,4↑5 | 1->4,4↑5 | |||
4->5,5↑5 | 2->5,5↑5 | 1->5,4↑5 |