题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1651
题目大意:有一条链p,有N个节点,需要你找到一条最短的链q。直接来看第二个条件,链q里面的节点的出现顺序必须和链p相同。其实也就找不出其它的条件了。大意就是经过一个节点两次,那么会形成一个环,在满足第二个条件的情况下把所有的环都去掉就行了。
这道题目已经被放了好几天了,刚开始的时候我并没有什么很好的思路,今天早上剪头发的时候突然想起这道题目,发现是个dp,然后就果断上来敲代码。大概的思路和普通dp差不多,关键是要求打印路径,那就涉及到一个路径还原,刚开始的时候这个路径还原的情况并没有考虑完善,直到wa哭了之后才找出错误的原因。具体怎么实现的我还是show me the code吧。
奉上代码,请多指教。
#include <iostream>
#include <cstdio>
#include <vector>
#include <stack>
#define pii pair<int, int>
#define x first
#define y second
using namespace std;
int main() {
int N;
scanf("%d", &N);
vector<int> vec(N);
for (int i = 0; i < N; ++i) scanf("%d", &vec[i]);
const int INF = 1e9 + 7;
vector<int> path(N, 0);
vector<pii> dp(10001, pii(INF, INF));
dp[vec[0]] = pii(0, 0);
for (int i = 1; i < N; ++i) {
//dp[vec[i]] = min(dp[vec[i]], dp[vec[i - 1]] + 1);
//在不用路径还原的情况下,原始的dp方程如上所示
if (dp[vec[i - 1]].x + 1 <= dp[vec[i]].x) {
dp[vec[i]].x = dp[vec[i - 1]].x + 1;
path[i] = i - 1;
dp[vec[i]].y = i - 1;//这里为什么要多加一维y?这是我WA了之后加上的,看看下面的else,想想题目中给出的测试数据就知道了
}
else path[i] = dp[vec[i]].y;
}
/
//下面就路径还原,随便什么数据结构来维护都行
stack<int> ans;
int e = N - 1;
while (vec[e] != vec[0]) {
ans.push(vec[e]);
e = path[e];
}
ans.push(vec[0]);
while (!ans.empty()) {
printf("%d ", ans.top());
ans.pop();
}
return 0;
}