您的位置:首页 > 其它

USACO 6.1.1 Postal Vans 特例dp

2018-02-10 20:57 267 查看
http://train.usaco.org/usacoprob2?a=iHzQON4VeJX&S=vans
题目大意:由4条横线,N条纵线划划分的网络,要求一条路线经过每个网点一次且仅一次,求共有多少条这样的路径

想法一:枚举,不可能,其实到第五章之后的题目好像都不太能枚举了
想法二:相当于先有一个最外层的大矩形轮廓,然后逐步“下凹”,只要下凹的那一格在当前外表面轮廓组成中只有一条边就不会使最后的结果缺失某个点,而且N确定时下凹的次数是固定的,但是要找到下凹的位置麻烦
想法三:与下凹相反,在网络中选择格子形成一个联通的区域,N确定时格子总数也是确定的,但是要求选择区域在任意位置宽度为一且四角的格子要被包含在这个区域中

正解:基于连通性状态压缩的动态规划
说实话以我现在的能力看不太懂,但这个方法绝对是具有普适性的,所以等以后再好好学习
链接:https://wenku.baidu.com/view/a6dce6c76137ee06eff918d1.html 陈丹琦

特解:因为这道题在横向上只有四条线,所以可以用普通的dp方法处理,真的妙
链接:http://blog.csdn.net/jiangshibiao/article/details/21446033
需要注意的一点就是最后的结果很大,当N = 1000时,结果的位数有400+位,需要自定大数类/*
ID: frontie1
TASK: vans
LANG: C++
*/
#include <iostream>
#include <cstdio>

using namespace std;

struct number
{
int arr[500];
int length;

number()
{
// for(int i = 0; i < 100; ++i){
// arr[i] = 0;
// }
length = 1;
}

number operator+(const number &obj)
{
// this->print();
// cout << " + ";
// obj.print();
// cout << " = ";
number output;
int cur1 = 0, cur2 = 0, cur3 = 0;
int up = 0;
while(cur1 < length && cur2 < obj.length){
output.arr[cur3] = arr[cur1] + obj.arr[cur2] + up;
up = output.arr[cur3] / 10;
output.arr[cur3] %= 10;
++cur1; ++cur2; ++cur3;
}
while(cur1 < length){
output.arr[cur3] = arr[cur1] + up;
up = output.arr[cur3] / 10;
output.arr[cur3] %= 10;
++cur1; ++cur3;
}
while(cur2 < obj.length){
output.arr[cur3] = obj.arr[cur2] + up;
up = output.arr[cur3] / 10;
output.arr[cur3] %= 10;
++cur2; ++cur3;
}
if(up){
output.arr[cur3] = up;
++cur3;
}
output.length = cur3;
// output.print();
// cout << endl;
return output;
}

number operator-(const number &obj)
{
// this->print();
// cout << " - ";
// obj.print();
// cout << " = ";
number output;
int cur1 = 0, cur2 = 0, cur3 = 0;
int down = 0;

while(cur1 < length && cur2 < obj.length){
output.arr[cur3] = arr[cur1] - obj.arr[cur2] - down;
if(output.arr[cur3] < 0){
//cout << output.arr[cur3] << " occurred" << endl;
output.arr[cur3] += 10;
down = 1;
}
else down = 0;
++cur1; ++cur2; ++cur3;
}
while(cur1 < length){
output.arr[cur3] = arr[cur1] - down;
if(output.arr[cur3] < 0){
output.arr[cur3] += 10;
down = 1;
}
else down = 0;
++cur1; ++cur3;
}
while(output.arr[cur3-1] == 0) --cur3;
output.length = cur3;
// output.print();
// cout << endl;
return output;
}

void print() const
{
for(int i = length-1; i >= 0; --i){
cout << arr[i];
}
}
};

int N;

number f[1010];
number g[1010];

//int f[1010];
//int g[1010];

int main()
{
//freopen("vans.in", "r", stdin);
//freopen("vans.out", "w", stdout);

cin >> N;

// f[1] = 0; f[2] = 2;
// g[1] = 2; g[2] = 2;
//
// for(int i = 3; i <= N; ++i){
// f[i] = g[i-1] + f[i-1];
// g[i] = 2*f[i-1] + g[i-1] + g[i-2] - g[i-3];
// cout << f[i] << '\t' << g[i] << endl;
// }

f[1].arr[0] = 0; f[2].arr[0] = 2; f[3].arr[0] = 4;
g[1].arr[0] = 2; g[2].arr[0] = 2; g[3].arr[0] = 8;

for(int i = 4; i <= N; ++i){
f[i] = g[i-1] + f[i-1];
g[i] = ((f[i-1] + f[i-1]) + (g[i-1] + g[i-2])) - g[i-3];
// f[i].print();
// cout << '\t';
// g[i].print();
// cout << endl;
}

f
.print();
cout << endl;
// cout << f
.length << endl;

// for(int i = f
.length-1; i >= 0; --i){
// cout << f
.arr[i];
// }
// cout << endl;

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  USACO